import { loadManifest } from "./lib/manifest.js";
import path from "path";
import { buildScriptsAndStyles } from "./lib/content-scripts.js";
import { extractInlineScriptsFromIndex } from "./lib/index-file.js";
import { normalizePath } from "vite";
import fs from "fs";

/**
 * Build addition assets required for the extension and pack it into the directory.
 * @param {PackExtensionSettings} settings Build settings.
 */
export async function packExtension(settings) {
  const manifest = loadManifest(path.resolve(settings.rootDir, 'manifest.json'));

  const replacementMapping = await buildScriptsAndStyles({
    inputs: manifest.collectContentScripts(),
    outputDir: settings.contentScriptsDir,
    rootDir: settings.rootDir,
  });

  await manifest.mapContentScripts(async entry => {
    if (entry.js) {
      entry.js = entry.js
        .map(jsSourcePath => {
          if (!replacementMapping.has(jsSourcePath)) {
            return [];
          }

          return replacementMapping.get(jsSourcePath);
        })
        .flat(1)
        .map(pathName => {
          return normalizePath(
            path.relative(
              settings.exportDir,
              path.join(
                settings.contentScriptsDir,
                pathName
              )
            )
          )
        });
    }

    if (entry.css) {
      entry.css = entry.css
        .map(jsSourcePath => {
          if (!replacementMapping.has(jsSourcePath)) {
            return [];
          }

          return replacementMapping.get(jsSourcePath);
        })
        .flat(1)
        .map(pathName => {
          return normalizePath(
            path.relative(
              settings.exportDir,
              path.join(
                settings.contentScriptsDir,
                pathName
              )
            )
          )
        })
    }

    return entry;
  })

  switch (process.env.SITE) {
    case 'derpibooru':
      manifest.replaceHostTo([
        'derpibooru.org',
        'trixiebooru.org'
      ]);
      manifest.replaceBooruNameWith('Derpibooru');
      manifest.setGeckoIdentifier('derpibooru-tagging-assistant@thecore.city');
      break;

    case 'tantabus':
      manifest.replaceHostTo('tantabus.ai');
      manifest.replaceBooruNameWith('Tantabus');
      manifest.setGeckoIdentifier('tantabus-tagging-assistant@thecore.city');
      break;

    default:
      if (process.env.SITE) {
        console.warn('No replacement set up for site: ' + process.env.SITE);
      }
  }

  manifest.passVersionFromPackage(path.resolve(settings.rootDir, 'package.json'));
  manifest.saveTo(path.resolve(settings.exportDir, 'manifest.json'));

  const iconsDirectory = path.resolve(settings.exportDir, 'icons');

  switch (process.env.SITE) {
    case "derpibooru":
    case "tantabus":
      const siteIconsDirectory = path.resolve(iconsDirectory, process.env.SITE);

      if (!fs.existsSync(siteIconsDirectory)) {
        console.warn(`Can't find replacement icons for site ${process.env.SITE}`);
        break;
      }

      console.log(`Found replacement icons for ${process.env.SITE}, swapping them...`);

      fs.readdirSync(siteIconsDirectory).forEach(fileName => {
        const originalIconPath = path.resolve(settings.exportDir, fileName);
        const replacementIconPath = path.resolve(siteIconsDirectory, fileName);

        if (!fs.existsSync(originalIconPath)) {
          console.warn(`Original icon not found: ${originalIconPath}`)
          return;
        }

        fs.rmSync(originalIconPath);
        fs.cpSync(replacementIconPath, originalIconPath);

        console.log(`Replaced: ${path.relative(settings.rootDir, replacementIconPath)} → ${path.relative(settings.rootDir, originalIconPath)}`);
      });

      break;
  }

  if (fs.existsSync(iconsDirectory)) {
    console.log('Cleaning up icon replacements directory');

    fs.rmSync(iconsDirectory, {
      recursive: true,
      force: true,
    });
  }

  extractInlineScriptsFromIndex(path.resolve(settings.exportDir, 'index.html'));
}

/**
 * @typedef {Object} PackExtensionSettings
 * @property {string} rootDir Root directory of the repository. Required for properly fetching source files.
 * @property {string} exportDir Directory of the built extension.
 * @property {string} contentScriptsDir Directory specifically for content scripts entries.
 */
