// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:dartdoc/src/generator/generator.dart';
import 'package:dartdoc/src/generator/generator_backend.dart';
import 'package:dartdoc/src/generator/html_resources.g.dart' as resources;
import 'package:dartdoc/src/generator/resource_loader.dart';
import 'package:dartdoc/src/generator/template_data.dart';
import 'package:dartdoc/src/model/model.dart';
import 'package:dartdoc/src/runtime_stats.dart';

/// Generator backend for HTML output.
class HtmlGeneratorBackend extends GeneratorBackend {
  HtmlGeneratorBackend(
      super.options, super.templates, super.writer, super.resourceProvider);

  @override
  void generateClass(PackageGraph packageGraph, Library library, Class class_) {
    super.generateClass(packageGraph, library, class_);
    var data = ClassTemplateData(options, packageGraph, library, class_);
    var sidebarContent = templates.renderSidebarForContainer(data);
    write(writer, class_.sidebarPath, data, sidebarContent, isSidebar: true);
    runtimeStats.incrementAccumulator('writtenSidebarFileCount');
  }

  @override
  void generateEnum(PackageGraph packageGraph, Library library, Enum enum_) {
    super.generateEnum(packageGraph, library, enum_);
    var data = EnumTemplateData(options, packageGraph, library, enum_);
    var sidebarContent = templates.renderSidebarForContainer(data);
    write(writer, enum_.sidebarPath, data, sidebarContent, isSidebar: true);
    runtimeStats.incrementAccumulator('writtenSidebarFileCount');
  }

  @override
  void generateExtension(
      PackageGraph packageGraph, Library library, Extension extension) {
    super.generateExtension(packageGraph, library, extension);
    var data = ExtensionTemplateData(options, packageGraph, library, extension);
    var sidebarContent = templates.renderSidebarForContainer(data);
    write(writer, extension.sidebarPath, data, sidebarContent, isSidebar: true);
    runtimeStats.incrementAccumulator('writtenSidebarFileCount');
  }

  @override
  void generateExtensionType(
      PackageGraph packageGraph, Library library, ExtensionType extensionType) {
    super.generateExtensionType(packageGraph, library, extensionType);
    var data = ExtensionTypeTemplateData(
        options, packageGraph, library, extensionType);
    var sidebarContent = templates.renderSidebarForContainer(data);
    write(writer, extensionType.sidebarPath, data, sidebarContent,
        isSidebar: true);
    runtimeStats.incrementAccumulator('writtenSidebarFileCount');
  }

  @override
  void generateLibrary(PackageGraph packageGraph, Library library) {
    super.generateLibrary(packageGraph, library);
    var data = LibraryTemplateData(options, packageGraph, library);
    var sidebarContent = templates.renderSidebarForLibrary(data);
    write(writer, library.sidebarPath, data, sidebarContent, isSidebar: true);
    runtimeStats.incrementAccumulator('writtenSidebarFileCount');
  }

  @override
  void generateMixin(PackageGraph packageGraph, Library library, Mixin mixin) {
    super.generateMixin(packageGraph, library, mixin);
    var data = MixinTemplateData(options, packageGraph, library, mixin);
    var sidebarContent = templates.renderSidebarForContainer(data);
    write(writer, mixin.sidebarPath, data, sidebarContent, isSidebar: true);
    runtimeStats.incrementAccumulator('writtenSidebarFileCount');
  }

  @override
  void generatePackage(PackageGraph packageGraph, Package package) {
    super.generatePackage(packageGraph, package);
    // We have to construct the data again. This only happens once per package.
    var data = PackageTemplateData(options, packageGraph, package);
    var dataForSearch =
        PackageTemplateDataForSearch(options, packageGraph, package);
    var content = templates.renderError(data);
    write(writer, '__404error.html', data, content);
    var searchContent = templates.renderSearchPage(dataForSearch);
    write(writer, 'search.html', data, searchContent);
  }

  @override
  Future<void> generateAdditionalFiles() async {
    await _copyResources(writer);
    var favicon = options.favicon;
    if (favicon != null) {
      // Allow overwrite of favicon.
      var bytes = resourceProvider.getFile(favicon).readAsBytesSync();
      writer.writeBytes(
        _pathJoin('static-assets', 'favicon.png'),
        bytes,
        allowOverwrite: true,
      );
    }
  }

  Future<void> _copyResources(FileWriter writer) async {
    var resourcesDir = options.resourcesDir ??
        (await resourceProvider.getResourceFolder(_dartdocResourcePrefix)).path;
    for (var resourceFileName in resources.resourceNames) {
      var destinationPath = _pathJoin('static-assets', resourceFileName);
      var sourcePath = _pathJoin(resourcesDir, resourceFileName);
      writer.writeBytes(
        destinationPath,
        resourceProvider.getFile(sourcePath).readAsBytesSync(),
      );
    }
  }

  String _pathJoin(String a, String b) =>
      resourceProvider.pathContext.join(a, b);

  static const _dartdocResourcePrefix = 'package:dartdoc/resources';
}
