
import { NextRequest, NextResponse } from 'next/server';
import { getServerSession } from 'next-auth';
import { authOptions } from "@/lib/auth";
import { PrismaClient } from '@prisma/client';
import { createGoogleClient, fetchGoogleTasks, fetchGoogleTaskLists } from '@/lib/google-tasks';
import { fetchMsTodoLists, fetchMsTodoTasks, isMsTodoTaskCompleted, fetchMsChecklistItems } from '@/lib/microsoft-todo';
import { getOutlookAccessToken } from '@/lib/outlook-token';

const prisma = new PrismaClient();

interface SourceList {
    id: string;
    title: string;
}

interface ImportedTask {
    title: string;
    description: string;
    externalId: string;
    externalListId: string;
    dueDate: Date | null;
    status: string;
    sourceListTitle: string;
    parentExternalId?: string;
}

export async function POST(req: NextRequest) {
    try {
        const session = await getServerSession(authOptions);
        if (!session?.user?.email) {
            return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
        }

        const body = await req.json();
        const { provider, sourceLists } = body;

        if (!provider || !['google', 'outlook', 'synology'].includes(provider)) {
            return NextResponse.json({ error: 'Invalid provider' }, { status: 400 });
        }

        const user = await prisma.user.findUnique({
            where: { email: session.user.email }
        });

        if (!user) {
            return NextResponse.json({ error: 'User not found' }, { status: 404 });
        }

        // Normalize sourceLists
        let lists: SourceList[] = [];
        if (Array.isArray(sourceLists)) {
            lists = sourceLists.map((item: any) =>
                typeof item === 'string'
                    ? { id: item, title: item }
                    : { id: item.id, title: item.title || item.id }
            );
        }

        const importedTasks: ImportedTask[] = [];
        let targetLists: SourceList[] = lists;

        if (provider === 'google') {
            const account = await prisma.account.findFirst({
                where: { userId: user.id, provider: { in: ['google-calendar', 'google'] } },
                orderBy: { provider: 'asc' }
            });

            if (!account || !account.access_token) {
                return NextResponse.json({ error: 'Google account not connected' }, { status: 400 });
            }

            const client = createGoogleClient(account.access_token, account.refresh_token || undefined);

            if (targetLists.length === 0) {
                const googleLists = await fetchGoogleTaskLists(client);
                if (googleLists.length > 0) {
                    targetLists = [{ id: googleLists[0].id, title: googleLists[0].title }];
                }
            }

            for (const sourceList of targetLists) {
                try {
                    const googleTasks = await fetchGoogleTasks(client, sourceList.id);
                    importedTasks.push(...googleTasks.map(t => ({
                        title: t.title,
                        description: t.notes || '',
                        externalId: t.id,
                        externalListId: sourceList.id,
                        dueDate: t.due ? new Date(t.due) : null,
                        status: t.status,
                        sourceListTitle: sourceList.title,
                        parentExternalId: t.parent || undefined,
                    })));
                } catch (e) {
                    console.error(`Error fetching Google tasks for list ${sourceList.id}:`, e);
                }
            }
        }

        if (provider === 'outlook') {
            const accessToken = await getOutlookAccessToken(user.id);
            if (!accessToken) {
                return NextResponse.json({ error: 'Outlook account not connected' }, { status: 400 });
            }

            if (targetLists.length === 0) {
                const msTodoLists = await fetchMsTodoLists(accessToken);
                if (msTodoLists.length > 0) {
                    const defaultList = msTodoLists.find(l => l.wellknownListName === 'defaultList') || msTodoLists[0];
                    targetLists = [{ id: defaultList.id, title: defaultList.displayName }];
                }
            }

            for (const sourceList of targetLists) {
                try {
                    const msTasks = await fetchMsTodoTasks(accessToken, sourceList.id);
                    for (const t of msTasks) {
                        importedTasks.push({
                            title: t.title,
                            description: t.body?.content || '',
                            externalId: t.id,
                            externalListId: sourceList.id,
                            dueDate: t.dueDateTime ? new Date(t.dueDateTime.dateTime) : null,
                            status: isMsTodoTaskCompleted(t.status) ? 'completed' : 'notStarted',
                            sourceListTitle: sourceList.title,
                        });

                        // Fetch checklist items as sub-tasks
                        try {
                            const checklistItems = await fetchMsChecklistItems(accessToken, sourceList.id, t.id);
                            for (const item of checklistItems) {
                                importedTasks.push({
                                    title: item.displayName,
                                    description: '',
                                    externalId: item.id,
                                    externalListId: sourceList.id,
                                    dueDate: null,
                                    status: item.isChecked ? 'completed' : 'notStarted',
                                    sourceListTitle: sourceList.title,
                                    parentExternalId: t.id,
                                });
                            }
                        } catch (e) {
                            console.error(`Error fetching checklist items for task ${t.id}:`, e);
                        }
                    }
                } catch (e) {
                    console.error(`Error fetching MS Todo tasks for list ${sourceList.id}:`, e);
                }
            }
        }

        if (provider === 'synology') {
            const connection = await prisma.calendarConnection.findFirst({
                where: { userId: user.id, provider: 'synology' }
            });

            if (!connection || !connection.accessToken || !connection.refreshToken) {
                return NextResponse.json({ error: 'Synology account not connected' }, { status: 400 });
            }

            const [username, password] = connection.accessToken.split(':');
            const serverUrl = connection.refreshToken;

            const { fetchSynologyReminderLists, fetchSynologyTasks } = await import('@/lib/synology-tasks');

            if (targetLists.length === 0) {
                const synoLists = await fetchSynologyReminderLists(serverUrl, username, password);
                if (synoLists.length > 0) {
                    targetLists = [{ id: synoLists[0].id, title: synoLists[0].title }];
                }
            }

            for (const sourceList of targetLists) {
                try {
                    const synoTasks = await fetchSynologyTasks(serverUrl, username, password, sourceList.id);
                    for (const t of synoTasks) {
                        importedTasks.push({
                            title: t.title,
                            description: t.notes || '',
                            externalId: t.id,
                            externalListId: sourceList.id,
                            dueDate: t.due ? new Date(t.due) : null,
                            status: t.status === 'completed' ? 'completed' : 'notStarted',
                            sourceListTitle: sourceList.title,
                        });
                    }
                } catch (e) {
                    console.error(`Error fetching Synology tasks for list ${sourceList.id}:`, e);
                }
            }
        }

        // Group tasks by source list title
        const tasksByList = new Map<string, ImportedTask[]>();
        // Pre-initialize with all target lists to ensure they are created even if empty
        for (const tl of targetLists) {
            tasksByList.set(tl.title, []);
        }

        for (const task of importedTasks) {
            const listTitle = task.sourceListTitle;
            if (!tasksByList.has(listTitle)) {
                tasksByList.set(listTitle, []);
            }
            tasksByList.get(listTitle)!.push(task);
        }

        console.log(`[IMPORT] Total tasks: ${importedTasks.length} across ${tasksByList.size} lists`);

        let count = 0;
        let updatedCount = 0;
        let listsCreated = 0;

        // Track externalId -> local task ID for parent-child linking
        const externalToLocalId = new Map<string, string>();
        // Tasks that need parent linking after creation
        const pendingParentLinks: { localId: string; parentExternalId: string }[] = [];

        // Build a lookup from list title to source list info (id, title)
        const listTitleToSource = new Map<string, SourceList>();
        for (const tl of targetLists) {
            listTitleToSource.set(tl.title, tl);
        }

        for (const [listTitle, tasks] of tasksByList) {
            const sourceInfo = listTitleToSource.get(listTitle);

            // Try to find by externalId first (more reliable), then by title
            let somedayList = sourceInfo
                ? await prisma.somedayList.findFirst({
                    where: { userId: user.id, externalId: sourceInfo.id, externalProvider: provider }
                })
                : null;

            if (!somedayList) {
                somedayList = await prisma.somedayList.findFirst({
                    where: { userId: user.id, title: listTitle }
                });
            }

            if (!somedayList) {
                somedayList = await prisma.somedayList.create({
                    data: {
                        userId: user.id,
                        title: listTitle,
                        order: 0,
                        externalId: sourceInfo?.id ?? null,
                        externalProvider: sourceInfo ? provider : null,
                        lastSyncedAt: new Date(),
                    }
                });
                listsCreated++;
                console.log(`[IMPORT] Created SomedayList "${listTitle}" (${somedayList.id}) with externalId=${sourceInfo?.id}`);
            } else if (sourceInfo && !somedayList.externalId) {
                // Update existing list with external link if missing
                somedayList = await prisma.somedayList.update({
                    where: { id: somedayList.id },
                    data: {
                        externalId: sourceInfo.id,
                        externalProvider: provider,
                        lastSyncedAt: new Date(),
                    }
                });
                console.log(`[IMPORT] Linked SomedayList "${listTitle}" to external ${sourceInfo.id}`);
            }

            // First pass: create/update all tasks (parents first via sorting)
            const sortedTasks = [...tasks].sort((a, b) => {
                // Parent tasks (no parentExternalId) come first
                if (!a.parentExternalId && b.parentExternalId) return -1;
                if (a.parentExternalId && !b.parentExternalId) return 1;
                return 0;
            });

            for (const task of sortedTasks) {
                const existingTask = await prisma.task.findFirst({
                    where: { userId: user.id, externalId: task.externalId, externalProvider: provider }
                });

                if (existingTask) {
                    await prisma.task.update({
                        where: { id: existingTask.id },
                        data: {
                            somedayListId: somedayList.id,
                            lastSyncedAt: new Date()
                        }
                    });
                    externalToLocalId.set(task.externalId, existingTask.id);
                    if (task.parentExternalId) {
                        pendingParentLinks.push({ localId: existingTask.id, parentExternalId: task.parentExternalId });
                    }
                    updatedCount++;
                } else {
                    const newTask = await prisma.task.create({
                        data: {
                            userId: user.id,
                            title: task.title,
                            description: task.description,
                            completed: task.status === 'completed' || task.status === 'COMPLETED',
                            somedayListId: somedayList.id,
                            externalId: task.externalId,
                            externalProvider: provider,
                            externalListId: task.externalListId,
                            lastSyncedAt: new Date()
                        }
                    });
                    externalToLocalId.set(task.externalId, newTask.id);
                    if (task.parentExternalId) {
                        pendingParentLinks.push({ localId: newTask.id, parentExternalId: task.parentExternalId });
                    }
                    count++;
                }
            }
        }

        // Second pass: link parent-child relationships
        for (const { localId, parentExternalId } of pendingParentLinks) {
            const parentLocalId = externalToLocalId.get(parentExternalId);
            if (parentLocalId) {
                await prisma.task.update({
                    where: { id: localId },
                    data: { parentTaskId: parentLocalId }
                });
            }
        }

        console.log(`[IMPORT] Done! Created: ${count}, Updated: ${updatedCount}, Lists created: ${listsCreated}`);
        return NextResponse.json({ success: true, count, updatedCount, listsCreated });

    } catch (error: unknown) {
        console.error('Import error:', error);
        const message = error instanceof Error ? error.message : 'Import failed';
        return NextResponse.json({ error: message }, { status: 500 });
    }
}
