// ============================================================
// scanner.ts — 文件扫描算法
//
// 基于 infinite_canvas_140.md §2.2-2.3 的分析实现：
//   - detectStage(filePath) — 从路径检测阶段
//   - groupKeyForPath(filePath, stage) — 提取分组键
//   - buildScanRoots(...) — 计算扫描根目录
//   - getStageExtensions(stage) — 阶段对应的文件扩展名
//   - shotNameMatchesQuery(shotName, query) — 镜头名称匹配
// ============================================================

import type { StageType } from '../stores/useCanvasStore';

// ---------- 阶段检测 ----------

/** 阶段映射：路径关键词 → StageType */
const STAGE_PATTERNS: Array<{ segment: string; stage: StageType }> = [
    { segment: 'Storyboard', stage: 'Storyboard' },
    { segment: 'Keyframe', stage: 'Keyframe' },
    { segment: 'Video', stage: 'Video' },
    { segment: 'Audio', stage: 'Audio' },
    { segment: 'LipSync', stage: 'LipSync' },
];

/**
 * 从文件路径中检测所属阶段。
 * 查找路径中是否包含阶段目录名（如 "/Storyboard/"）。
 * Assets 阶段特殊处理：路径中含有 "/assets/" 即为 Assets。
 */
export function detectStage(filePath: string): StageType {
    const normalized = filePath.replace(/\\/g, '/');
    for (const { segment, stage } of STAGE_PATTERNS) {
        if (normalized.includes(`/${segment}/`)) {
            return stage;
        }
    }
    if (normalized.includes('/assets/')) {
        return 'Assets';
    }
    return 'Storyboard'; // 默认
}

// ---------- 分组键提取 ----------

/**
 * 从文件路径中提取分组键。
 *
 * Assets 阶段：
 *   向上找到 assets/ 目录 → 下一层为 type（chr/prp/set）
 *   → 再下一层为 name（角色名/道具名/场景名）
 *   → 返回 "chr/主角A"
 *
 * 非 Assets 阶段：
 *   向上找到 shots/ 目录 → 下一层为 episode（E01）
 *   → 再下一层为 shot（SC001）
 *   → 返回 "E01/SC001"
 */
export function groupKeyForPath(filePath: string, stage: StageType): string {
    const normalized = filePath.replace(/\\/g, '/');

    if (stage === 'Assets') {
        const parts = normalized.split('/');
        const assetsIdx = parts.lastIndexOf('assets');
        if (assetsIdx >= 0 && assetsIdx + 2 < parts.length) {
            const assetType = parts[assetsIdx + 1]; // chr / prp / set
            const assetName = parts[assetsIdx + 2]; // 角色名 / 道具名 / 场景名
            return `${assetType}/${assetName}`;
        }
        return 'assets/unknown';
    }

    // 非 Assets：查找 shots/ 目录
    const parts = normalized.split('/');
    const shotsIdx = parts.lastIndexOf('shots');
    if (shotsIdx >= 0 && shotsIdx + 2 < parts.length) {
        const episode = parts[shotsIdx + 1]; // E01
        const shot = parts[shotsIdx + 2]; // SC001
        return `${episode}/${shot}`;
    }
    return 'unknown/unknown';
}

/** 从路径中提取集数名（如 "E01"） */
export function extractEpisodeName(filePath: string): string {
    const normalized = filePath.replace(/\\/g, '/');
    const parts = normalized.split('/');
    const shotsIdx = parts.lastIndexOf('shots');
    if (shotsIdx >= 0 && shotsIdx + 1 < parts.length) {
        return parts[shotsIdx + 1];
    }
    return '';
}

/** 从路径中提取镜头名（如 "SC001"） */
export function extractShotName(filePath: string): string {
    const normalized = filePath.replace(/\\/g, '/');
    const parts = normalized.split('/');
    const shotsIdx = parts.lastIndexOf('shots');
    if (shotsIdx >= 0 && shotsIdx + 2 < parts.length) {
        return parts[shotsIdx + 2];
    }
    return '';
}

// ---------- 扫描根目录计算 ----------

/** 资产类型筛选 */
export type AssetTypeFilter = '全部' | '角色' | '道具' | '场景';

/** buildScanRoots 参数 */
export interface BuildScanRootsParams {
    projectPath: string;
    episodePath: string | null;
    stage: StageType;
    assetTypeFilter: AssetTypeFilter;
    shotQuery: string;
}

/**
 * 计算文件扫描的根目录列表。
 *
 * Assets 阶段：
 *   "全部" → [project/assets/]
 *   "角色" → [project/assets/chr/]
 *   "道具" → [project/assets/prp/]
 *   "场景" → [project/assets/set/]
 *
 * 非 Assets 阶段：
 *   遍历 project/shots/ 下的所有集数目录，
 *   对每个集数遍历所有 shot 子目录，
 *   追加 {shotDir}/{stage}/
 *   若指定 shotQuery → 仅匹配的镜头
 */
export function buildScanRoots(params: BuildScanRootsParams): string[] {
    const { projectPath, episodePath, stage, assetTypeFilter, shotQuery } = params;

    if (stage === 'Assets') {
        const assetsDir = `${projectPath}/assets`;
        switch (assetTypeFilter) {
            case '角色':
                return [`${assetsDir}/chr`];
            case '道具':
                return [`${assetsDir}/prp`];
            case '场景':
                return [`${assetsDir}/set`];
            default:
                return [assetsDir];
        }
    }

    // 非 Assets：遍历 shots/ 目录
    const shotsDir = `${projectPath}/shots`;
    const fs = requireNodeFs();
    if (!fs || !fs.existsSync(shotsDir)) return [];

    const roots: string[] = [];
    const episodes = episodePath
        ? [episodePath]
        : fs.readdirSync(shotsDir).filter((name: string) => {
              const full = `${shotsDir}/${name}`;
              return (
                  !name.startsWith('.') &&
                  fs.statSync(full).isDirectory()
              );
          });

    for (const ep of episodes) {
        const epDir = episodePath || `${shotsDir}/${ep}`;
        if (!fs.existsSync(epDir)) continue;

        const shotNames = fs.readdirSync(epDir).filter((name: string) => {
            const full = `${epDir}/${name}`;
            return (
                !name.startsWith('.') &&
                fs.statSync(full).isDirectory()
            );
        });

        for (const shot of shotNames) {
            // shotQuery 过滤
            if (shotQuery && !shotNameMatchesQuery(shot, shotQuery)) continue;

            const stageDir = `${epDir}/${shot}/${stage}`;
            if (fs.existsSync(stageDir)) {
                roots.push(stageDir);
            }
        }
    }

    return roots;
}

// ---------- Shot 名称匹配 ----------

/**
 * 镜头名称匹配算法（§11.3）。
 *
 * - query 为空 → 匹配所有
 * - query.toUpperCase() in shotName.toUpperCase() → 匹配
 * - query 为纯数字 → 提取 shotName 中所有数字位后比较 → 匹配
 *
 * 例：query="1" 匹配 "SC001"、"SC010"、"EP01_SHOT_1"
 */
export function shotNameMatchesQuery(shotName: string, query: string): boolean {
    if (!query) return true;
    const upperShot = shotName.toUpperCase();
    const upperQuery = query.toUpperCase();
    if (upperShot.includes(upperQuery)) return true;
    // 纯数字匹配：提取 shotName 中的所有数字位
    if (/^\d+$/.test(query)) {
        const digits = upperShot.replace(/\D/g, '');
        if (digits.includes(query)) return true;
    }
    return false;
}

// ---------- 阶段扩展名映射 ----------

/**
 * 每个阶段允许的文件扩展名（不含点，小写）。
 */
export function getStageExtensions(stage: StageType): string[] {
    switch (stage) {
        case 'Storyboard':
        case 'Keyframe':
            return ['jpg', 'jpeg', 'png', 'webp', 'bmp', 'gif'];
        case 'Video':
            return ['mp4', 'webm', 'mov', 'avi', 'mkv'];
        case 'Audio':
        case 'LipSync':
            return ['mp3', 'wav', 'ogg', 'flac', 'aac', 'm4a'];
        case 'Assets':
            return ['jpg', 'jpeg', 'png', 'webp', 'bmp', 'gif', 'mp4', 'webm'];
    }
}

// ---------- 内部工具 ----------

/**
 * 尝试获取 Node.js fs 模块（仅在 Electron 环境可用）。
 * 渲染进程中通过 vite-plugin-electron-renderer 暴露。
 * 注意：此处仅用于 buildScanRoots 中的同步读取目录结构（低频操作）。
 *       大量文件扫描走 IPC → 主进程。
 */
function requireNodeFs(): typeof import('fs') | null {
    try {
        // eslint-disable-next-line @typescript-eslint/no-require-imports
        return require('fs');
    } catch {
        return null;
    }
}
