import { createHash } from "node:crypto";
import { existsSync, readFileSync, readdirSync, statSync } from "node:fs";
import { homedir } from "node:os";
import { basename, dirname, extname, isAbsolute, join, relative, resolve, sep } from "node:path";

import { WP4_07_REAL_RESOURCE_VERSIONS } from "./wp4-07-fixture.mjs";

const dynamicFontTemplates = Object.freeze({
  "15974853bc3294ef68e7e6d58fe74fd7": "DYN002",
  "46f8336813e4c48d06a1aef294fdccf6": "DYN016",
  "53ca6b704728520da50c145eabb2e635": "DYN007",
  cca5efc0e02fb1bf62349bd68ef30fc1: "DYN015",
  dd25b35dcb7ba4476cbaa9a9592e39e2: "DYN001",
  e4210c9872f0c279b35273f230809821: "DYN011",
  f4bfd4132df2d6be97ceabadf3853505: "DYN008",
});

const dynamicImages = Object.freeze({
  "DYN001-image28": ["DYN001", "image28.png"],
  "DYN002-image29": ["DYN002", "image29.png"],
  "DYN003-image30": ["DYN003", "image30.png"],
  "DYN004-image32": ["DYN004", "image32.png"],
  "DYN008-backendui0": ["DYN008", "backendui0.png"],
  "DYN011-backendui0": ["DYN011", "backendui0.png"],
  "DYN015-imager2": ["DYN015", "imager2_2.png"],
  "DYN016-image21": ["DYN016", "image21.png"],
});

function sha256(path) {
  return createHash("sha256").update(readFileSync(path)).digest("hex").toUpperCase();
}

function walkFiles(directory) {
  return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => {
    const path = join(directory, entry.name);
    return entry.isDirectory() ? walkFiles(path) : [path];
  });
}

function firstFile(directory, predicate) {
  const path = walkFiles(directory).find(predicate);
  if (!path) throw new Error(`WP4_07_REAL_ASSET_FILE_MISSING:${basename(directory)}`);
  return path;
}

function inside(root, path) {
  const delta = relative(resolve(root), resolve(path));
  return delta !== ".." && !delta.startsWith(`..${sep}`) && !isAbsolute(delta);
}

function contentType(path) {
  const extension = extname(path).toLowerCase();
  if (extension === ".png") return "image/png";
  if (extension === ".otf") return "font/otf";
  if (extension === ".woff") return "font/woff";
  if (extension === ".woff2") return "font/woff2";
  return "font/ttf";
}

function assetRecord(assetId, path, sourceReference, expectedSha256) {
  if (!existsSync(path) || !statSync(path).isFile()) throw new Error(`WP4_07_REAL_ASSET_UNAVAILABLE:${assetId}`);
  const actualSha256 = sha256(path);
  if (expectedSha256 && actualSha256 !== expectedSha256) throw new Error(`WP4_07_REAL_ASSET_HASH_MISMATCH:${assetId}`);
  return {
    asset_id: assetId,
    bytes: statSync(path).size,
    content_type: contentType(path),
    path,
    sha256: actualSha256,
    source_reference: sourceReference,
  };
}

export function loadWp407RealAssets() {
  const manifestPath = resolve(process.env.DADA_WP4_07_FINAL_ASSET_MANIFEST ?? "");
  if (!process.env.DADA_WP4_07_FINAL_ASSET_MANIFEST || !existsSync(manifestPath)) throw new Error("WP4_07_FINAL_ASSET_MANIFEST_REQUIRED");
  const replicationRoot = resolve(process.env.DADA_REPLICATION_ASSET_ROOT ?? join(homedir(), "Desktop", "sticker_web_replication_assets"));
  const handoffPath = resolve(process.env.DADA_COMPLEX_ASSET_MANIFEST ?? join(replicationRoot, "sticker_web_handoff", "sticker_web_catalog_manifest.json"));
  const staticRoot = resolve(process.env.DADA_STATIC_STICKER_ROOT ?? join(replicationRoot, "sticker_normal"));
  const backgroundPath = resolve(process.env.DADA_WP4_07_BACKGROUND_PATH ?? join(homedir(), "Documents", "贴纸脚本", "time_01_input_20260716.png"));
  if (!existsSync(handoffPath) || !existsSync(staticRoot)) throw new Error("WP4_07_REAL_ARCHIVE_ROOT_REQUIRED");

  const manifestRaw = readFileSync(manifestPath, "utf8");
  const manifest = JSON.parse(manifestRaw);
  const handoff = JSON.parse(readFileSync(handoffPath, "utf8"));
  const collectionRoots = Object.fromEntries(handoff.collections.map((collection) => [collection.id, resolve(dirname(handoffPath), collection.root)]));
  const fontRoot = collectionRoots.font_panel;
  const dynamicRoot = collectionRoots.interactive_stickers;
  if (!fontRoot || !dynamicRoot) throw new Error("WP4_07_REAL_ARCHIVE_COLLECTION_REQUIRED");

  const publicAssets = new Map();
  for (const item of manifest.assets.font_panel_items) {
    const packageDirectory = resolve(fontRoot, item.canonical_resource_reference.path);
    if (!inside(fontRoot, packageDirectory)) throw new Error(`WP4_07_UNSAFE_FONT_REFERENCE:${item.canonical_id}`);
    const path = firstFile(resolve(packageDirectory, "font_files"), (candidate) => /\.(?:otf|ttf|woff2?|ztf)$/i.test(candidate));
    publicAssets.set(item.canonical_id, assetRecord(item.canonical_id, path, `font_panel/${item.canonical_id}/${basename(path)}`));
  }

  for (const item of manifest.assets.static_stickers) {
    const path = resolve(staticRoot, item.relative_path);
    if (!inside(staticRoot, path)) throw new Error(`WP4_07_UNSAFE_STATIC_REFERENCE:${item.stable_id}`);
    publicAssets.set(item.stable_id, assetRecord(item.stable_id, path, `static/${item.stable_id}`, item.sha256));
  }

  for (const [assetId, templateId] of Object.entries(dynamicFontTemplates)) {
    const directory = resolve(dynamicRoot, "templates", templateId, "fonts", assetId);
    const path = firstFile(directory, (candidate) => /\.(?:otf|ttf|woff2?|ztf)$/i.test(candidate));
    publicAssets.set(assetId, assetRecord(assetId, path, `interactive/${templateId}/fonts/${assetId}/${basename(path)}`));
  }
  for (const [assetId, [templateId, filename]] of Object.entries(dynamicImages)) {
    const path = resolve(dynamicRoot, "templates", templateId, "resource", filename);
    publicAssets.set(assetId, assetRecord(assetId, path, `interactive/${templateId}/resource/${filename}`));
  }

  const background = assetRecord("private-background", backgroundPath, "private/background/time_01_input_20260716.png");
  const manifestSha256 = createHash("sha256").update(manifestRaw).digest("hex").toUpperCase();
  return {
    background,
    evidence: {
      asset_count: publicAssets.size,
      assets: [...publicAssets.values()].map(({ asset_id, bytes, content_type, sha256: hash, source_reference }) => ({
        asset_id, bytes, content_type, sha256: hash, source_reference,
      })),
      background: { bytes: background.bytes, content_type: background.content_type, sha256: background.sha256, source_reference: background.source_reference },
      manifest_sha256: manifestSha256,
      release_version: manifest.release_version,
      resource_versions: WP4_07_REAL_RESOURCE_VERSIONS,
      source_mutations: 0,
    },
    publicAssets,
  };
}
