﻿"use client";

import React, { createContext, useContext, useRef, useState, useCallback } from "react";
import { useEditorStore } from "@/lib/store";
import JSZip from "jszip";

interface ImportContextType {
    triggerImport: (parentId?: string | null) => void;
    isImporting: boolean;
}

class ImportApiError extends Error {
    status: number;
    detail: string;

    constructor(message: string, status: number, detail: string) {
        super(message);
        this.status = status;
        this.detail = detail;
    }
}

const ImportContext = createContext<ImportContextType | undefined>(undefined);

export function ImportProvider({ children }: { children: React.ReactNode }) {
    const [isImporting, setIsImporting] = useState(false);
    const fileInputRef = useRef<HTMLInputElement>(null);
    const targetParentIdRef = useRef<string | null>(null);
    const { pages, fetchPages } = useEditorStore();

    const postPage = useCallback(
        async (
            payload: {
                title: string;
                content?: string;
                importMarkdown?: string;
                parentId?: string | null;
                type: "file" | "folder";
            },
            contextLabel: string
        ) => {
            const res = await fetch("/api/pages", {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(payload),
                credentials: "same-origin",
            });

            if (!res.ok) {
                let detail = "";
                try {
                    const data = await res.json();
                    detail = typeof data?.error === "string" ? data.error : JSON.stringify(data);
                } catch {
                    detail = await res.text();
                }
                throw new ImportApiError(`${contextLabel}失败（${res.status}）${detail ? `: ${detail}` : ""}`, res.status, detail);
            }

            return res.json();
        },
        []
    );

    const putPage = useCallback(
        async (
            id: string,
            payload: {
                title?: string;
                content?: string;
                importMarkdown?: string;
                parentId?: string | null;
                type?: "file" | "folder";
            },
            contextLabel: string
        ) => {
            const res = await fetch(`/api/pages/${id}`, {
                method: "PUT",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify(payload),
                credentials: "same-origin",
            });

            if (!res.ok) {
                let detail = "";
                try {
                    const data = await res.json();
                    detail = typeof data?.error === "string" ? data.error : JSON.stringify(data);
                } catch {
                    detail = await res.text();
                }
                throw new ImportApiError(`${contextLabel}失败（${res.status}）${detail ? `: ${detail}` : ""}`, res.status, detail);
            }

            return res.json();
        },
        []
    );

    const triggerImport = useCallback((parentId: string | null = null) => {
        targetParentIdRef.current = parentId;
        if (fileInputRef.current) {
            fileInputRef.current.value = "";
            fileInputRef.current.click();
        }
    }, []);

    const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0];
        if (!file) return;

        setIsImporting(true);
        try {
            if (file.name.toLowerCase().endsWith(".zip")) {
                await handleZipImport(file);
            } else {
                await handleSingleFileImport(file);
            }
        } catch (error) {
            console.error("Import failed", error);
            const message = error instanceof Error ? error.message : "导入失败，请检查文件";
            alert(message);
        } finally {
            setIsImporting(false);
            fetchPages();
        }
    };

    const handleSingleFileImport = async (file: File) => {
        const text = await file.text();
        const title = file.name.replace(/\.md$/i, "");
        // 直接存储原始 Markdown，tiptap-markdown 扩展会在编辑器加载时自动解析
        const parentId = targetParentIdRef.current;
        const existing = pages.find((p) => p.type === "file" && p.parentId === parentId && (p.title || "").trim() === title.trim());
        if (existing) {
            await putPage(
                existing.id,
                {
                    title,
                    content: text,
                    parentId,
                    type: "file",
                },
                "更新导入文件"
            );
            return;
        }

        await postPage(
            {
                title,
                content: text,
                parentId,
                type: "file",
            },
            "创建导入文件"
        );
    };

    const handleZipImport = async (file: File) => {
        const zip = await JSZip.loadAsync(file);

        const rootName = file.name.replace(/(\.md)?\.zip$/i, "");
        let rootFolder: { id: string };

        try {
            rootFolder = await postPage(
                {
                    title: rootName,
                    parentId: targetParentIdRef.current,
                    type: "folder",
                },
                "创建导入根目录"
            );
        } catch (error) {
            const invalidParent =
                error instanceof ImportApiError && error.status === 400 && /Parent folder not found/i.test(error.detail);
            if (!invalidParent || !targetParentIdRef.current) {
                throw error;
            }
            // Parent folder may have been deleted; fallback to root level and continue import.
            rootFolder = await postPage(
                {
                    title: rootName,
                    parentId: null,
                    type: "folder",
                },
                "创建导入根目录"
            );
        }

        const rootId = rootFolder.id;

        const fileEntries: { path: string; file: JSZip.JSZipObject }[] = [];
        const folderPaths = new Set<string>();

        zip.forEach((relativePath, zipEntry) => {
            if (relativePath.startsWith("__MACOSX") || relativePath.includes("/.") || relativePath.startsWith(".")) return;

            if (zipEntry.dir) {
                const cleanPath = relativePath.endsWith("/") ? relativePath.slice(0, -1) : relativePath;
                if (cleanPath) folderPaths.add(cleanPath);
            } else {
                fileEntries.push({ path: relativePath, file: zipEntry });
                const parts = relativePath.split("/");
                let currentPath = "";
                for (let i = 0; i < parts.length - 1; i += 1) {
                    currentPath = currentPath ? `${currentPath}/${parts[i]}` : parts[i];
                    folderPaths.add(currentPath);
                }
            }
        });

        const pathMap = new Map<string, string>();
        pathMap.set("", rootId);

        const sortedFolders = Array.from(folderPaths).sort((a, b) => a.split("/").length - b.split("/").length);

        for (const folderPath of sortedFolders) {
            const parts = folderPath.split("/");
            const name = parts[parts.length - 1];
            const parentPath = parts.slice(0, -1).join("/");
            const parentId = pathMap.get(parentPath);

            if (!parentId) {
                console.warn(`Parent not found for ${folderPath}, skipping`);
                continue;
            }

            const folder = await postPage(
                {
                    title: name,
                    parentId,
                    type: "folder",
                },
                `创建目录 ${folderPath}`
            );
            pathMap.set(folderPath, folder.id);
        }

        for (const { path, file: zipFile } of fileEntries) {
            const parts = path.split("/");
            const fileName = parts.pop() || "";
            const parentPath = parts.join("/");
            const parentId = pathMap.get(parentPath);

            if (!parentId) continue;
            if (!fileName.endsWith(".md") && !fileName.endsWith(".txt")) continue;

            const markdown = await zipFile.async("string");
            const title = fileName.replace(/\.md$/i, "").replace(/\.txt$/i, "");
            const existing = pages.find((p) => p.type === "file" && p.parentId === parentId && (p.title || "").trim() === title.trim());
            if (existing) {
                await putPage(
                    existing.id,
                    {
                        title,
                        content: markdown,
                        parentId,
                        type: "file",
                    },
                    `更新文件 ${path}`
                );
            } else {
                await postPage(
                    {
                        title,
                        content: markdown,
                        parentId,
                        type: "file",
                    },
                    `创建文件 ${path}`
                );
            }
        }
    };

    return (
        <ImportContext.Provider value={{ triggerImport, isImporting }}>
            {children}
            <input
                type="file"
                ref={fileInputRef}
                onChange={handleFileChange}
                className="hidden"
                accept=".md,.txt,.zip"
            />
        </ImportContext.Provider>
    );
}

export function useImport() {
    const context = useContext(ImportContext);
    if (!context) {
        throw new Error("useImport must be used within an ImportProvider");
    }
    return context;
}
