import "server-only";

import path from "path";
import { promises as fs } from "fs";
import type { MediaAsset } from "@/types/media";
import { getDocumentsBaseDir, getLegacyMindmapsBaseDir } from "@/lib/server/local-paths";

const tryAccess = async (file: string) => {
  try {
    await fs.access(file);
    return true;
  } catch {
    return false;
  }
};

export async function detectLocalMindmapDocs(docIds: string[]): Promise<string[]> {
  const results: string[] = [];
  const preferredBaseDir = getDocumentsBaseDir();
  const legacyBaseDir = getLegacyMindmapsBaseDir();
  for (const id of docIds) {
    const folder = path.join(preferredBaseDir, id);
    const preferredLegacy = path.join(folder, "mindmap.json");
    const legacy = path.join(legacyBaseDir, id, "mindmap.json");
    let has = false;
    if ((await tryAccess(preferredLegacy)) || (await tryAccess(legacy))) {
      has = true;
    } else {
      try {
        const entries = await fs.readdir(folder);
        has = entries.some((name) => /^mindmap-.+\.json$/i.test(name));
      } catch {
        has = false;
      }
    }
    if (has) {
      results.push(id);
    }
  }
  return results;
}

export type LocalMindmapFile = {
  documentId: string;
  mindmapId: string;
  fileName: string;
  source: "preferred" | "legacy";
};

export async function detectLocalMindmapFiles(docIds: string[]): Promise<LocalMindmapFile[]> {
  const results: LocalMindmapFile[] = [];
  const preferredBaseDir = getDocumentsBaseDir();
  const legacyBaseDir = getLegacyMindmapsBaseDir();
  for (const id of docIds) {
    const folder = path.join(preferredBaseDir, id);
    try {
      const entries = await fs.readdir(folder);
      for (const name of entries) {
        if (name === "mindmap.json") {
          // mindmap.json 属于旧版单文件导图：mindmapId 必须包含 docId，避免不同页面间 ID 冲突
          results.push({
            documentId: id,
            mindmapId: `legacy-${id}`,
            fileName: name,
            source: "preferred",
          });
          continue;
        }
        const m = /^mindmap-(.+)\.json$/i.exec(name);
        if (m && m[1]) {
          results.push({ documentId: id, mindmapId: m[1], fileName: name, source: "preferred" });
        }
      }
    } catch {
      // ignore
    }

    // 旧目录（仅支持 mindmap.json）
    const legacy = path.join(legacyBaseDir, id, "mindmap.json");
    if (await tryAccess(legacy)) {
      results.push({
        documentId: id,
        mindmapId: `legacy-${id}`,
        fileName: "mindmap.json",
        source: "legacy",
      });
    }
  }
  return results;
}

function extractMindmapImageAssetIdsFromData(input: unknown): string[] {
  const root = (() => {
    if (!input || typeof input !== "object") return input;
    const record = input;
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    return (record && typeof record === "object" && "root" in (record as any)) ? (record as any).root : input;
  })();

  const ids: string[] = [];
  const seen = new Set<string>();

  const push = (value: unknown) => {
    if (typeof value !== "string") return;
    if (!value.startsWith("asset:")) return;
    const id = value.slice("asset:".length).trim();
    if (!id) return;
    if (seen.has(id)) return;
    seen.add(id);
    ids.push(id);
  };

  const get = (obj: unknown, key: string): unknown => {
    if (!obj || typeof obj !== "object") return undefined;
    return (obj as Record<string, unknown>)[key];
  };

  const walk = (node: unknown) => {
    if (!node || typeof node !== "object") return;

    const data = get(node, "data");
    const image = get(node, "image");

    // 常见：node.data.image = "asset:xxx"
    push(get(data, "image"));

    // 兼容：node.image = "asset:xxx"
    push(image);

    // 兼容：node.image.url = "asset:xxx"
    push(get(image, "url"));

    // 兼容：node.data.image.url = "asset:xxx"
    push(get(get(data, "image"), "url"));

    const children = get(node, "children");
    if (Array.isArray(children)) {
      children.forEach(walk);
    }
  };

  walk(root);
  return ids;
}

type TrashedMindmapMeta = {
  docId: string;
  mindmapId: string;
  originalFileName: string;
  originalPath: string;
  trashedFileName: string;
  deleted_at: string;
};

async function tryReadJsonFile<T>(file: string): Promise<T | null> {
  try {
    const content = await fs.readFile(file, "utf8");
    return JSON.parse(content) as T;
  } catch {
    return null;
  }
}

export async function detectLocalMindmapImageAssetIdsByMindmapId(
  files: LocalMindmapFile[],
): Promise<Record<string, string[]>> {
  const mapping: Record<string, string[]> = {};
  const preferredBaseDir = getDocumentsBaseDir();
  const legacyBaseDir = getLegacyMindmapsBaseDir();

  for (const item of files) {
    const baseDir = item.source === "legacy" ? legacyBaseDir : preferredBaseDir;
    const filePath = path.join(baseDir, item.documentId, item.fileName);
    const data = await tryReadJsonFile<unknown>(filePath);
    if (!data) continue;
    const ids = extractMindmapImageAssetIdsFromData(data);
    if (ids.length > 0) {
      mapping[item.mindmapId] = ids;
    }
  }

  return mapping;
}

async function listTrashMetasForFolder(folder: string): Promise<TrashedMindmapMeta[]> {
  const trashDir = path.join(folder, ".trash");
  try {
    const entries = await fs.readdir(trashDir);
    const metas: TrashedMindmapMeta[] = [];
    for (const name of entries) {
      if (!name.endsWith(".deleted.json")) continue;
      const metaPath = path.join(trashDir, name);
      const meta = await tryReadJsonFile<TrashedMindmapMeta>(metaPath);
      if (meta?.docId && meta?.mindmapId && meta?.trashedFileName && meta?.deleted_at) {
        // 若原路径已存在（用户撤销/恢复），则不再展示为垃圾桶记录，避免堆积。
        try {
          await fs.access(meta.originalPath);
          await fs.rm(path.join(trashDir, meta.trashedFileName), { force: true });
          await fs.rm(metaPath, { force: true });
          continue;
        } catch {
          // ignore
        }
        metas.push(meta);
      }
    }
    return metas;
  } catch {
    return [];
  }
}

export async function detectLocalTrashedMindmapAssets(
  workspaceId: string,
  docIds: string[],
): Promise<MediaAsset[]> {
  const results: MediaAsset[] = [];
  const preferredBaseDir = getDocumentsBaseDir();
  const legacyBaseDir = getLegacyMindmapsBaseDir();

  for (const docId of docIds) {
    const preferredFolder = path.join(preferredBaseDir, docId);
    const legacyFolder = path.join(legacyBaseDir, docId);
    const metas = [
      ...(await listTrashMetasForFolder(preferredFolder)),
      ...(await listTrashMetasForFolder(legacyFolder)),
    ];

    metas.forEach((meta) => {
      results.push({
        id: meta.mindmapId,
        workspace_id: workspaceId,
        document_id: docId,
        asset_type: "mindmap",
        file_url: null,
        thumbnail_url: null,
        bucket: null,
        storage_path: null,
        file_name: meta.originalFileName,
        file_size: null,
        mime_type: "application/json",
        ocr_payload: undefined,
        ocr_strategy: null,
        ocr_text: null,
        ocr_status: null,
        deleted_at: meta.deleted_at,
        deleted_by: null,
        purged_at: null,
        signed_url: null,
        created_at: "",
        updated_at: "",
      });
    });
  }

  results.sort((a, b) => (b.deleted_at ?? "").localeCompare(a.deleted_at ?? ""));
  return results;
}

