"use client";

import { useEffect, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { X, Upload, Search, Loader2 } from "lucide-react";
import {
    uploadStandaloneDocument,
    uploadProjectDocument,
    addDocumentToProject,
    deleteDocument,
} from "@/app/lib/mikeApi";
import type { MikeDocument } from "./types";
import { FileDirectory } from "./FileDirectory";
import { useDirectoryData, invalidateDirectoryCache } from "./useDirectoryData";
import { OwnerOnlyModal } from "./OwnerOnlyModal";
import { useAuth } from "@/contexts/AuthContext";

export { invalidateDirectoryCache };

interface Props {
    open: boolean;
    onClose: () => void;
    onSelect: (documents: MikeDocument[], projectId?: string) => void;
    breadcrumb: string[];
    allowMultiple?: boolean;
    projectId?: string;
}

export function AddDocumentsModal({
    open,
    onClose,
    onSelect,
    breadcrumb,
    allowMultiple = true,
    projectId,
}: Props) {
    const { loading, standaloneDocuments, projects } = useDirectoryData(open);
    const { user } = useAuth();
    const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
    const [uploading, setUploading] = useState(false);
    const [search, setSearch] = useState("");
    const [extraUploadedDocs, setExtraUploadedDocs] = useState<MikeDocument[]>([]);
    // IDs deleted in this session — hidden locally since `useDirectoryData`'s
    // cached state won't re-fetch until the modal reopens.
    const [deletedIds, setDeletedIds] = useState<Set<string>>(new Set());
    const [ownerOnlyAction, setOwnerOnlyAction] = useState<string | null>(null);
    const fileInputRef = useRef<HTMLInputElement>(null);

    useEffect(() => {
        if (!open) return;
        setSearch("");
        setSelectedIds(new Set());
        setExtraUploadedDocs([]);
        setDeletedIds(new Set());
    }, [open]);

    if (!open) return null;

    const q = search.toLowerCase().trim();

    const allStandalone = [
        ...extraUploadedDocs.filter(
            (u) => !standaloneDocuments.some((d) => d.id === u.id),
        ),
        ...standaloneDocuments,
    ].filter((d) => !deletedIds.has(d.id));

    const filteredStandalone = q
        ? allStandalone.filter((d) => d.filename.toLowerCase().includes(q))
        : allStandalone;

    const filteredProjects = projects
        .filter((p) => p.id !== projectId)
        .map((p) => ({
            ...p,
            documents: (p.documents || []).filter(
                (d) =>
                    !deletedIds.has(d.id) &&
                    (!q || d.filename.toLowerCase().includes(q)),
            ),
        }))
        .filter(
            (p) =>
                !q ||
                p.name.toLowerCase().includes(q) ||
                p.documents.length > 0,
        );

    const allDocs = [
        ...allStandalone,
        ...projects.flatMap((p) => p.documents || []),
    ];

    async function handleConfirm() {
        const selected = allDocs.filter((d) => selectedIds.has(d.id));

        if (projectId) {
            const toAssign = selected.filter((d) => d.project_id !== projectId);
            const alreadyHere = selected.filter(
                (d) => d.project_id === projectId,
            );
            if (toAssign.length > 0) {
                setUploading(true);
                try {
                    const assigned = await Promise.all(
                        toAssign.map((d) =>
                            addDocumentToProject(projectId, d.id),
                        ),
                    );
                    onSelect([...alreadyHere, ...assigned], projectId);
                } catch (err) {
                    console.error("Failed to assign documents:", err);
                } finally {
                    setUploading(false);
                }
            } else {
                onSelect(alreadyHere, projectId);
            }
            onClose();
            return;
        }

        const projectIds = new Set(
            selected.map((d) => d.project_id).filter(Boolean),
        );
        const singleProjectId =
            projectIds.size === 1 ? [...projectIds][0]! : undefined;
        onSelect(selected, singleProjectId);
        onClose();
    }

    async function handleDelete(ids: string[]) {
        // Server only allows the doc creator to delete. Filter to owned
        // and warn for the rest.
        const docsById = new Map<string, MikeDocument>();
        for (const d of [
            ...standaloneDocuments,
            ...extraUploadedDocs,
            ...projects.flatMap((p) => p.documents ?? []),
        ]) {
            docsById.set(d.id, d);
        }
        const owned = ids.filter((id) => {
            const d = docsById.get(id);
            return !d || !d.user_id || !user?.id || d.user_id === user.id;
        });
        const blocked = ids.length - owned.length;
        if (owned.length === 0 && blocked > 0) {
            setOwnerOnlyAction(
                "delete these documents — only the document creator can delete a document",
            );
            return;
        }
        const idSet = new Set(owned);
        try {
            await Promise.all(owned.map((id) => deleteDocument(id)));
        } catch (err) {
            console.error("Delete failed:", err);
            return;
        }
        invalidateDirectoryCache();
        setExtraUploadedDocs((prev) => prev.filter((d) => !idSet.has(d.id)));
        setDeletedIds((prev) => {
            const next = new Set(prev);
            owned.forEach((id) => next.add(id));
            return next;
        });
        if (blocked > 0) {
            setOwnerOnlyAction(
                `delete ${blocked} of the selected documents — only the document creator can delete a document`,
            );
        }
    }

    async function handleUpload(e: React.ChangeEvent<HTMLInputElement>) {
        const files = Array.from(e.target.files || []);
        if (!files.length) return;
        setUploading(true);
        try {
            const uploaded = await Promise.all(
                files.map((f) =>
                    projectId
                        ? uploadProjectDocument(projectId, f)
                        : uploadStandaloneDocument(f),
                ),
            );
            invalidateDirectoryCache();
            setExtraUploadedDocs((prev) => [...uploaded, ...prev]);
            uploaded.forEach((d) =>
                setSelectedIds((prev) => new Set([...prev, d.id])),
            );
        } catch (err) {
            console.error("Upload failed:", err);
        } finally {
            setUploading(false);
            if (fileInputRef.current) fileInputRef.current.value = "";
        }
    }

    return createPortal(
        <div className="fixed inset-0 z-[200] flex items-center justify-center bg-black/10 backdrop-blur-xs">
            <div className="w-full max-w-2xl rounded-2xl bg-white shadow-2xl flex flex-col h-[600px]">
                {/* Header */}
                <div className="flex items-center justify-between px-5 py-4">
                    <div className="flex items-center gap-1.5 text-xs text-gray-400">
                        {breadcrumb.map((segment, i) => (
                            <span key={i} className="flex items-center gap-1.5">
                                {i > 0 && <span>›</span>}
                                {segment}
                            </span>
                        ))}
                    </div>
                    <button
                        onClick={onClose}
                        className="rounded-lg p-1.5 text-gray-400 hover:bg-gray-100 hover:text-gray-600"
                    >
                        <X className="h-4 w-4" />
                    </button>
                </div>

                {/* Search bar */}
                <div className="px-4 pt-1 pb-2">
                    <div className="flex items-center gap-2 rounded-lg border border-gray-200 bg-gray-50 px-3 py-2">
                        <Search className="h-3.5 w-3.5 text-gray-400 shrink-0" />
                        <input
                            type="text"
                            placeholder="Search…"
                            value={search}
                            onChange={(e) => setSearch(e.target.value)}
                            className="flex-1 bg-transparent text-sm text-gray-700 placeholder:text-gray-400 outline-none"
                            autoFocus
                        />
                        {search && (
                            <button
                                onClick={() => setSearch("")}
                                className="text-gray-400 hover:text-gray-600"
                            >
                                <X className="h-3.5 w-3.5" />
                            </button>
                        )}
                    </div>
                </div>

                {/* File browser */}
                <div className="flex-1 overflow-y-auto px-4 pb-2">
                    <FileDirectory
                        standaloneDocs={filteredStandalone}
                        directoryProjects={filteredProjects}
                        loading={loading}
                        selectedIds={selectedIds}
                        onChange={setSelectedIds}
                        allowMultiple={allowMultiple}
                        forceExpanded={!!q}
                        emptyMessage={
                            q ? "No matches found" : "No documents yet"
                        }
                        onDelete={handleDelete}
                    />
                </div>

                {/* Footer */}
                <div className="border-t border-gray-100 px-4 py-3 flex items-center justify-between gap-3">
                    <div>
                        <input
                            ref={fileInputRef}
                            type="file"
                            accept=".pdf,.docx,.doc"
                            multiple
                            className="hidden"
                            onChange={handleUpload}
                        />
                        <button
                            onClick={() => fileInputRef.current?.click()}
                            disabled={uploading}
                            className="flex items-center gap-1.5 rounded-lg border border-gray-200 px-3 py-1.5 text-sm text-gray-600 hover:bg-gray-50 disabled:opacity-50"
                        >
                            {uploading ? (
                                <Loader2 className="h-3.5 w-3.5 animate-spin" />
                            ) : (
                                <Upload className="h-3.5 w-3.5" />
                            )}
                            {uploading ? "Uploading…" : "Upload"}
                        </button>
                    </div>
                    <div className="flex items-center gap-2">
                        {selectedIds.size > 0 && (
                            <span className="text-xs text-gray-400">
                                {selectedIds.size} selected
                            </span>
                        )}
                        <button
                            onClick={onClose}
                            className="rounded-lg px-3 py-1.5 text-sm text-gray-500 hover:bg-gray-100"
                        >
                            Cancel
                        </button>
                        <button
                            onClick={handleConfirm}
                            disabled={selectedIds.size === 0 || uploading}
                            className="rounded-lg bg-gray-900 px-4 py-1.5 text-sm font-medium text-white hover:bg-gray-700 disabled:opacity-40"
                        >
                            {uploading ? "Saving…" : "Confirm"}
                        </button>
                    </div>
                </div>
            </div>
            <OwnerOnlyModal
                open={!!ownerOnlyAction}
                action={ownerOnlyAction ?? undefined}
                onClose={() => setOwnerOnlyAction(null)}
            />
        </div>,
        document.body,
    );
}
