import { NextResponse } from 'next/server';
import { prisma } from '@/lib/prisma';
import type { Prisma } from '@prisma/client';
import { requireApiAuth } from '@/lib/api-auth';
import { cleanupAccidentalStandaloneInlineCode, markdownToImportHtml } from '@/lib/markdown-import';
import { MAX_TITLE_LENGTH, safeParseTags, normalizeTags } from '@/lib/page-utils';

type PageRef = { id: string; parentId: string | null };

function buildChildrenMap(pages: PageRef[]): Map<string | null, string[]> {
    const childrenMap = new Map<string | null, string[]>();
    for (const page of pages) {
        const siblings = childrenMap.get(page.parentId) || [];
        siblings.push(page.id);
        childrenMap.set(page.parentId, siblings);
    }
    return childrenMap;
}

function isCycleMove(pages: PageRef[], nodeId: string, targetParentId: string): boolean {
    const parentMap = new Map<string, string | null>(pages.map((p) => [p.id, p.parentId]));
    let cursor: string | null = targetParentId;

    while (cursor) {
        if (cursor === nodeId) return true;
        cursor = parentMap.get(cursor) ?? null;
    }

    return false;
}

function collectDeleteOrder(rootId: string, pages: PageRef[]): string[] {
    const childrenMap = buildChildrenMap(pages);
    const order: string[] = [];

    const walk = (id: string) => {
        const children = childrenMap.get(id) || [];
        for (const childId of children) walk(childId);
        order.push(id);
    };

    walk(rootId);
    return order;
}

export async function GET(
    request: Request,
    { params }: { params: Promise<{ id: string }> }
) {
    const authError = await requireApiAuth();
    if (authError) return authError;

    const id = (await params).id;
    try {
        const page = await prisma.page.findUnique({
            where: { id },
        });
        if (!page) return NextResponse.json({ error: 'Page not found' }, { status: 404 });
        return NextResponse.json({ ...page, tags: safeParseTags(page.tags) });
    } catch {
        return NextResponse.json({ error: 'Error fetching page' }, { status: 500 });
    }
}

export async function PUT(
    request: Request,
    { params }: { params: Promise<{ id: string }> }
) {
    const authError = await requireApiAuth();
    if (authError) return authError;

    const id = (await params).id;
    try {
        const body = await request.json().catch(() => null);
        if (!body || typeof body !== 'object') {
            return NextResponse.json({ error: 'Invalid request body' }, { status: 400 });
        }

        const current = await prisma.page.findUnique({ where: { id }, select: { id: true } });
        if (!current) {
            return NextResponse.json({ error: 'Page not found' }, { status: 404 });
        }

        const updateData: Prisma.PageUncheckedUpdateInput = {};

        if (body.title !== undefined) {
            if (typeof body.title !== 'string') {
                return NextResponse.json({ error: 'Invalid title' }, { status: 400 });
            }
            const trimmed = body.title.trim();
            if (trimmed.length > MAX_TITLE_LENGTH) {
                return NextResponse.json({ error: 'Invalid title' }, { status: 400 });
            }
            updateData.title = trimmed || '无标题';
        }

        if (body.content !== undefined || body.importMarkdown !== undefined) {
            if (body.content !== undefined && typeof body.content !== 'string') {
                return NextResponse.json({ error: 'Invalid content' }, { status: 400 });
            }
            if (body.importMarkdown !== undefined && typeof body.importMarkdown !== 'string') {
                return NextResponse.json({ error: 'Invalid importMarkdown' }, { status: 400 });
            }
            const source = typeof body.importMarkdown === 'string' ? markdownToImportHtml(body.importMarkdown) : (body.content as string);
            updateData.content = cleanupAccidentalStandaloneInlineCode(source);
            if (typeof body.importMarkdown === 'string' && process.env.NODE_ENV !== 'production') {
                const lines = body.importMarkdown.replace(/\r\n?/g, '\n').split('\n');
                const fenceLines = lines
                    .map((line: string, idx: number) => (line.trimStart().startsWith('```') || line.trimStart().startsWith('~~~') ? idx + 1 : -1))
                    .filter((n: number) => n > 0);
                const preEnd = String(updateData.content || '').indexOf('</code></pre>');
                console.info(`[import-md][PUT] id=${id} fences=${fenceLines.join(',') || 'none'} preEnd=${preEnd} len=${String(updateData.content || '').length}`);
            }
        }

        if (body.icon !== undefined) {
            updateData.icon = typeof body.icon === 'string' ? body.icon : null;
        }

        if (body.isLocked !== undefined) {
            if (typeof body.isLocked !== 'boolean') {
                return NextResponse.json({ error: 'Invalid isLocked' }, { status: 400 });
            }
            updateData.isLocked = body.isLocked;
        }

        if (body.tags !== undefined) {
            updateData.tags = JSON.stringify(normalizeTags(body.tags));
        }

        if (body.parentId !== undefined) {
            if (body.parentId === null) {
                updateData.parentId = null;
            } else if (typeof body.parentId === 'string') {
                const targetParentId = body.parentId;
                if (targetParentId === id) {
                    return NextResponse.json({ error: 'Invalid parentId' }, { status: 400 });
                }

                const targetParent = await prisma.page.findUnique({
                    where: { id: targetParentId },
                    select: { id: true, type: true },
                });
                if (!targetParent || targetParent.type !== 'folder') {
                    return NextResponse.json({ error: 'Parent folder not found' }, { status: 400 });
                }

                const refs = await prisma.page.findMany({ select: { id: true, parentId: true } });
                if (isCycleMove(refs, id, targetParentId)) {
                    return NextResponse.json({ error: 'Cannot move page into its own subtree' }, { status: 400 });
                }

                updateData.parentId = targetParentId;
            } else {
                return NextResponse.json({ error: 'Invalid parentId' }, { status: 400 });
            }
        }

        if (body.order !== undefined) {
            if (!Number.isInteger(body.order)) {
                return NextResponse.json({ error: 'Invalid order' }, { status: 400 });
            }
            updateData.order = body.order;
        }

        const page = await prisma.page.update({
            where: { id },
            data: updateData,
        });
        return NextResponse.json({ ...page, tags: safeParseTags(page.tags) });
    } catch {
        return NextResponse.json({ error: 'Error updating page' }, { status: 500 });
    }
}

export async function DELETE(
    request: Request,
    { params }: { params: Promise<{ id: string }> }
) {
    const authError = await requireApiAuth();
    if (authError) return authError;

    const id = (await params).id;
    try {
        const refs = await prisma.page.findMany({ select: { id: true, parentId: true } });
        const exists = refs.some((p) => p.id === id);
        if (!exists) {
            return NextResponse.json({ error: 'Page not found' }, { status: 404 });
        }

        const deleteOrder = collectDeleteOrder(id, refs);
        await prisma.$transaction(async (tx) => {
            for (const pageId of deleteOrder) {
                await tx.page.delete({ where: { id: pageId } });
            }
        });

        return NextResponse.json({ success: true });
    } catch {
        return NextResponse.json({ error: 'Error deleting page' }, { status: 500 });
    }
}


