import JSZip from "jszip";
import { saveAs } from "file-saver";
import { Page } from "./store";
import { useSettingsStore } from "./settings-store";
import { sanitizeFilename } from "./page-utils";
import { htmlToMarkdown } from "./markdown-codec";

// Helper to escape YAML strings
function escapeYamlString(str: string): string {
    return str.replace(/"/g, '\\"');
}

/**
 * Converts a page to Markdown with Frontmatter
 */
export function pageToMarkdown(page: Page): string {
    const rawMarkdown = htmlToMarkdown(page.content || "");
    const tags = page.tags ? JSON.parse(typeof page.tags === 'string' ? page.tags : JSON.stringify(page.tags)) : [];

    // Format Date to Local Time with Timezone
    const dateObj = page.updatedAt ? new Date(page.updatedAt) : new Date();

    // Get timezone from store
    const { timezone } = useSettingsStore.getState();

    // Use Intl to format date in the target timezone
    // We want format: YYYY-MM-DDTHH:mm:ss
    // Since Intl isn't extremely flexible with custom formats without parts, we can use "sv-SE" locale which is usually ISO-like (YYYY-MM-DD HH:mm:ss)
    // Or just construct it using parts.

    let localDate;
    try {
        const options: Intl.DateTimeFormatOptions = {
            timeZone: timezone || "Asia/Shanghai",
            year: 'numeric',
            month: '2-digit',
            day: '2-digit',
            hour: '2-digit',
            minute: '2-digit',
            second: '2-digit',
            hour12: false
        };
        // sv-SE outputs YYYY-MM-DD HH:mm:ss
        const parts = new Intl.DateTimeFormat('sv-SE', options).formatToParts(dateObj);
        const getPart = (type: string) => parts.find(p => p.type === type)?.value || "";
        localDate = `${getPart('year')}-${getPart('month')}-${getPart('day')}T${getPart('hour')}:${getPart('minute')}:${getPart('second')}`;
    } catch {
        // Fallback if timezone is invalid
        localDate = dateObj.toISOString().slice(0, 19);
    }

    // Construct Frontmatter
    const frontmatter = [
        "---",
        `title: "${escapeYamlString(page.title)}"`,
        `id: "${page.id}"`,
        `date: "${localDate}"`,
        `tags: [${tags.map((t: string) => `"${escapeYamlString(t)}"`).join(", ")}]`,
        `order: ${page.order || 0}`,
        "---",
        "",
        ""
    ].join("\n");

    return frontmatter + rawMarkdown;
}

/**
 * Exports a single page as a Markdown file
 */
export function exportPageAsMarkdown(page: Page) {
    const markdown = pageToMarkdown(page);
    const blob = new Blob([markdown], { type: "text/markdown;charset=utf-8" });
    const filename = sanitizeFilename(page.title || "Untitled");
    saveAs(blob, `${filename}.md`);
}

/**
 * Exports a folder and its contents as a Zip file
 */
export async function exportFolderAsZip(folderId: string, allPages: Page[], folderName: string) {
    const zip = new JSZip();
    const cleanFolderName = sanitizeFilename(folderName);
    const folder = zip.folder(cleanFolderName);

    if (!folder) {
        console.error("Failed to create zip folder");
        return;
    }

    addPagesToZipRecursive(folder, folderId, allPages);

    try {
        const content = await zip.generateAsync({ type: "blob" });
        saveAs(content, `${folderName}.zip`);
    } catch (e) {
        console.error("Failed to generate zip", e);
    }
}

/**
 * Exports ALL pages as a Zip backup
 */
export async function exportAllPagesAsZip(allPages: Page[]) {
    const zip = new JSZip();
    const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 16); // YYYY-MM-DDTHH-mm
    const zipName = `noteai-backup-${timestamp}`;

    // Root level pages (parentId is null)
    addPagesToZipRecursive(zip, null, allPages);

    try {
        const content = await zip.generateAsync({ type: "blob" });
        saveAs(content, `${zipName}.zip`);
    } catch (e) {
        console.error("Failed to generate backup zip", e);
        throw e;
    }
}

// Helper to recursively add pages to zip
function addPagesToZipRecursive(currentFolder: JSZip, parentId: string | null, allPages: Page[]) {
    const children = allPages.filter(p => p.parentId === parentId);

    children.forEach(page => {
        const cleanTitle = sanitizeFilename(page.title);

        if (page.type === 'folder') {
            const subFolder = currentFolder.folder(cleanTitle);
            if (subFolder) {
                // Determine if we should look for children with this page's ID
                addPagesToZipRecursive(subFolder, page.id, allPages);
            }
        } else {
            const markdown = pageToMarkdown(page);
            // Handle duplicate filenames by appending ID if necessary? 
            // For simplicity, we assume titles are unique enough or zip handles overwrite (last wins).
            // Better: just append a counter if exists, but JSZip might overwrite.
            currentFolder.file(`${cleanTitle}.md`, markdown);
        }
    });
}
