// ============================================================
// LocalFileDataSource — 离线模式：Electron IPC → 本地文件系统
//
// 所有文件系统操作通过 window.canvas（preload 注入）桥接到主进程。
// 非 Electron 环境（浏览器开发模式）降级返回空数据/抛出友好错误。
// ============================================================

import { hasIpc, safeIpcInvoke } from '@/shared/utils/bus';
import { BIDIRECTIONAL } from '@shared/constants/ipc-channels';
import type {
    ICanvasDataSource,
    ScanRequest,
    ScanEntry,
    ScanProgressCallback,
    SidecarMetadata,
    ThumbnailRequest,
    ThumbnailResult,
    DataSourceCapabilities,
} from './ICanvasDataSource';

// ---------- IPC 返回类型 ----------

/** scanDirectory IPC 返回类型 */
type ScanDirResult = { success: boolean; data: ScanEntry[]; error?: string };

/** readSidecar / writeSidecar IPC 返回类型 */
type SidecarResult = { success: boolean; data: SidecarMetadata | null; error?: string };
type WriteSidecarResult = { success: boolean; error?: string };

/** generateThumbnail IPC 返回类型 */
type ThumbnailResultIpc = { success: boolean; data: ThumbnailResult; error?: string };

/** copyFile IPC 返回类型 */
type CopyFileResult = { success: boolean; data: string; error?: string };

/** 通用文件操作返回类型 */
type FileExistsResult = { success: boolean; data: boolean };
type FileDialogResult = { canceled: boolean; filePaths: string[] };
type FileReadResult = { success: boolean; data: string };

// ---------- 辅助 ----------

/** 检查 canvas API 是否可用 */
function hasCanvasApi(): boolean {
    return hasIpc() && typeof window.canvas !== 'undefined';
}

/** 包装 IPC 调用：非 Electron 环境抛出友好错误 */
async function requireCanvasApi(): Promise<void> {
    if (!hasCanvasApi()) {
        throw new Error('当前环境不支持文件系统操作。请在 HeiXiu 桌面应用中打开无限画布。');
    }
}

// ---------- 实现 ----------

export class LocalFileDataSource implements ICanvasDataSource {
    readonly capabilities: DataSourceCapabilities = {
        offline: true,
        realtime: false,
        thumbnails: true,
    };

    async scanDirectory(
        request: ScanRequest,
        _onProgress?: ScanProgressCallback,
    ): Promise<ScanEntry[]> {
        await requireCanvasApi();
        const result = (await window.canvas.scanDirectory({
            roots: request.roots,
            extensions: request.extensions,
            recursive: request.recursive,
        })) as ScanDirResult;
        if (!result.success) {
            throw new Error(result.error || '目录扫描失败');
        }
        return result.data;
    }

    async scanProject(params: {
        projectPath: string;
        stage: string;
        assetTypeFilter: string;
        shotQuery: string;
    }): Promise<ScanEntry[]> {
        await requireCanvasApi();
        console.log('[LocalFileDataSource] 📡 scanProject IPC → 主进程', params);
        const t0 = performance.now();
        const result = (await window.canvas.scanProject(params)) as ScanDirResult;
        const elapsed = (performance.now() - t0).toFixed(0);
        if (!result.success) {
            console.error(`[LocalFileDataSource] ❌ scanProject 失败 (${elapsed}ms):`, result.error);
            throw new Error(result.error || '项目扫描失败');
        }
        console.log(`[LocalFileDataSource] ✅ scanProject 返回 (${elapsed}ms): ${result.data.length} 条`);
        return result.data;
    }

    async readSidecar(filePath: string): Promise<SidecarMetadata | null> {
        await requireCanvasApi();
        const result = (await window.canvas.readSidecar({ filePath })) as SidecarResult;
        if (!result.success) return null;
        return result.data;
    }

    async writeSidecar(filePath: string, metadata: SidecarMetadata): Promise<void> {
        await requireCanvasApi();
        const result = (await window.canvas.writeSidecar({
            filePath,
            metadata,
        })) as WriteSidecarResult;
        if (!result.success) {
            throw new Error(result.error || '写入元数据失败');
        }
    }

    async generateThumbnail(request: ThumbnailRequest): Promise<ThumbnailResult> {
        await requireCanvasApi();
        const result = (await window.canvas.generateThumbnail({
            filePath: request.filePath,
            size: request.size,
        })) as ThumbnailResultIpc;
        if (!result.success) {
            throw new Error(result.error || '生成缩略图失败');
        }
        return result.data;
    }

    async readFileData(filePath: string): Promise<string | null> {
        await requireCanvasApi();
        const result = (await safeIpcInvoke(BIDIRECTIONAL.FILE_READ, {
            relativePath: filePath,
        })) as FileReadResult | undefined;
        return result?.success ? result.data : null;
    }

    async getFileUrl(filePath: string): Promise<string> {
        const ext = filePath.split('.').pop()?.toLowerCase() || '';
        const imageExts = ['jpg', 'jpeg', 'png', 'webp', 'bmp', 'gif'];
        if (imageExts.includes(ext)) {
            try {
                const thumb = await this.generateThumbnail({ filePath, size: 1024 });
                return `data:${thumb.mimeType};base64,${thumb.data}`;
            } catch {
                return `file://${filePath}`;
            }
        }
        return `file://${filePath}`;
    }

    async fileExists(filePath: string): Promise<boolean> {
        await requireCanvasApi();
        const result = (await safeIpcInvoke(BIDIRECTIONAL.FILE_EXISTS, {
            relativePath: filePath,
        })) as FileExistsResult | undefined;
        return result?.success ? result.data : false;
    }

    async copyFile(src: string, destDir: string, fileName: string): Promise<string> {
        await requireCanvasApi();
        const result = (await window.canvas.copyFile({
            src,
            destDir,
            fileName,
        })) as CopyFileResult;
        if (!result.success) {
            throw new Error(result.error || '复制文件失败');
        }
        return result.data;
    }

    async deleteFile(filePath: string): Promise<void> {
        await requireCanvasApi();
        await safeIpcInvoke(BIDIRECTIONAL.FILE_DELETE, { relativePath: filePath });
        const sidecarPath = filePath.replace(/\.[^.]+$/, '.json');
        await safeIpcInvoke(BIDIRECTIONAL.FILE_DELETE, { relativePath: sidecarPath });
    }

    async openDirectoryDialog(): Promise<string | null> {
        await requireCanvasApi();
        const result = (await safeIpcInvoke(BIDIRECTIONAL.FILE_DIALOG, {
            title: '选择工作区根目录',
            properties: ['openDirectory'],
        })) as FileDialogResult | undefined;
        if (!result || result.canceled || result.filePaths.length === 0) return null;
        return result.filePaths[0];
    }

    async listSubdirs(parentPath: string): Promise<string[]> {
        await requireCanvasApi();
        const result = (await window.canvas.listSubdirs({ parentPath })) as {
            success: boolean;
            data: string[];
            error?: string;
        };
        if (!result.success) {
            throw new Error(result.error || '列出子目录失败');
        }
        return result.data;
    }

    async scanStageFiles(params: {
        projectPath: string;
        episode: string;
        shot: string;
        stage: string;
    }): Promise<ScanEntry[]> {
        await requireCanvasApi();
        console.log('[LocalFileDataSource] 📡 scanStageFiles IPC → 主进程', params);
        const t0 = performance.now();
        const result = (await window.canvas.scanStageFiles(params)) as ScanDirResult;
        const elapsed = (performance.now() - t0).toFixed(0);
        if (!result.success) {
            console.error(`[LocalFileDataSource] ❌ scanStageFiles 失败 (${elapsed}ms):`, result.error);
            throw new Error(result.error || '扫描阶段文件失败');
        }
        console.log(`[LocalFileDataSource] ✅ scanStageFiles 返回 (${elapsed}ms): ${result.data.length} 条`);
        return result.data;
    }

    async scanAssetFiles(params: {
        projectPath: string;
        assetTypeFilter: string;
    }): Promise<ScanEntry[]> {
        await requireCanvasApi();
        console.log('[LocalFileDataSource] 📡 scanAssetFiles IPC → 主进程', params);
        const t0 = performance.now();
        const result = (await window.canvas.scanAssetFiles(params)) as ScanDirResult;
        const elapsed = (performance.now() - t0).toFixed(0);
        if (!result.success) {
            console.error(`[LocalFileDataSource] ❌ scanAssetFiles 失败 (${elapsed}ms):`, result.error);
            throw new Error(result.error || '扫描资产文件失败');
        }
        console.log(`[LocalFileDataSource] ✅ scanAssetFiles 返回 (${elapsed}ms): ${result.data.length} 条`);
        return result.data;
    }

    async createDirectory(parentPath: string, dirName: string): Promise<string> {
        await requireCanvasApi();
        console.log('[LocalFileDataSource] 📡 createDirectory IPC → 主进程', { parentPath, dirName });
        const result = (await window.canvas.createDirectory({ parentPath, dirName })) as {
            success: boolean;
            data: string;
            error?: string;
        };
        if (!result.success) {
            console.error('[LocalFileDataSource] ❌ createDirectory 失败:', result.error);
            throw new Error(result.error || '创建目录失败');
        }
        console.log('[LocalFileDataSource] ✅ createDirectory 成功:', result.data);
        return result.data;
    }
}
