import React, { useState, useCallback } from "react";

import { Spinner } from "@/lib/components/ui/spinner";
import { useConfigContext, useDownload, useIsProjectOwner, useIndexingSSE, useChatContext } from "@/lib/hooks";
import { useProjectArtifacts } from "@/lib/api/projects/hooks";
import { useProjectContext } from "@/lib/providers";
import type { ArtifactInfo, Project } from "@/lib/types";
import { validateFileSizes, validateBatchUploadSize, validateProjectSizeLimit, calculateTotalFileSize } from "@/lib/utils";

import { ArtifactBar } from "../chat/artifact";
import { FileDetails } from "../chat/file";
import { FileUpload, MessageBanner } from "../common";

import { AddProjectFilesDialog } from "./AddProjectFilesDialog";
import { EditFileDescriptionDialog } from "./EditFileDescriptionDialog";
import { FileDetailsDialog } from "./FileDetailsDialog";
import { DeleteProjectFileDialog } from "./DeleteProjectFileDialog";

interface KnowledgeSectionProps {
    project: Project;
    isDisabled?: boolean;
    onFileChange?: () => void;
}

export const KnowledgeSection = ({ project, isDisabled = false, onFileChange }: KnowledgeSectionProps) => {
    const isOwner = useIsProjectOwner(project.userId);
    const { data: artifacts = [], isLoading, error, refetch } = useProjectArtifacts(project.id);
    const { addFilesToProject, removeFileFromProject, updateFileMetadata } = useProjectContext();
    const { addNotification } = useChatContext();
    const { onDownload } = useDownload(project.id);
    const { startIndexing } = useIndexingSSE({ resourceId: project.id });
    const { validationLimits } = useConfigContext();

    // Get validation limits from config - if not available, skip client-side validation
    const maxPerFileUploadSizeBytes = validationLimits?.maxPerFileUploadSizeBytes;
    const maxBatchUploadSizeBytes = validationLimits?.maxBatchUploadSizeBytes;
    const maxProjectSizeBytes = validationLimits?.maxProjectSizeBytes;

    const [filesToUpload, setFilesToUpload] = useState<FileList | null>(null);
    const [isSubmitting, setIsSubmitting] = useState(false);
    const [selectedArtifact, setSelectedArtifact] = useState<ArtifactInfo | null>(null);
    const [showDetailsDialog, setShowDetailsDialog] = useState(false);
    const [expandedArtifact, setExpandedArtifact] = useState<string | null>(null);
    const [showEditDialog, setShowEditDialog] = useState(false);
    const [isSavingMetadata, setIsSavingMetadata] = useState(false);
    const [uploadError, setUploadError] = useState<string | null>(null);
    const [fileToDelete, setFileToDelete] = useState<ArtifactInfo | null>(null);

    const sortedArtifacts = React.useMemo(() => {
        return [...artifacts].sort((a, b) => {
            const dateA = a.last_modified ? new Date(a.last_modified).getTime() : 0;
            const dateB = b.last_modified ? new Date(b.last_modified).getTime() : 0;
            return dateB - dateA;
        });
    }, [artifacts]);

    const currentProjectArtifactSizeBytes = React.useMemo(() => {
        return calculateTotalFileSize(artifacts);
    }, [artifacts]);

    const handleValidateFileSizes = useCallback(
        (files: FileList) => {
            const fileSizeResult = validateFileSizes(files, { maxSizeBytes: maxPerFileUploadSizeBytes });
            if (!fileSizeResult.valid) {
                return fileSizeResult;
            }

            const batchSizeResult = validateBatchUploadSize(files, maxBatchUploadSizeBytes);
            if (!batchSizeResult.valid) {
                return batchSizeResult;
            }

            const projectSizeLimitResult = validateProjectSizeLimit(currentProjectArtifactSizeBytes, files, maxProjectSizeBytes);
            if (!projectSizeLimitResult.valid) {
                return { valid: false, error: projectSizeLimitResult.error };
            }

            return { valid: true };
        },
        [maxPerFileUploadSizeBytes, maxBatchUploadSizeBytes, maxProjectSizeBytes, currentProjectArtifactSizeBytes]
    );

    const handleFileUploadChange = (files: FileList | null) => {
        setFilesToUpload(files);
    };

    const handleConfirmUpload = async (formData: FormData) => {
        setIsSubmitting(true);
        setUploadError(null);

        try {
            const result = await addFilesToProject(project.id, formData);
            onFileChange?.();

            // close dialog and then start indexing if required
            setFilesToUpload(null);
            if (result.sseLocation) {
                startIndexing(result.sseLocation, project.id, "upload");
            }

            await refetch();
            addNotification("Upload completed", "success");
        } catch (e) {
            console.error("Failed to add files:", e);
            const errorMessage = e instanceof Error ? e.message : "Failed to upload files. Please try again.";
            setUploadError(errorMessage);
        } finally {
            setIsSubmitting(false);
        }
    };

    const handleCloseUploadDialog = () => {
        setFilesToUpload(null);
        setUploadError(null);
    };

    const handleClearUploadError = () => {
        setUploadError(null);
    };

    const handleDeleteClick = (artifact: ArtifactInfo) => {
        setFileToDelete(artifact);
    };

    const handleConfirmDelete = async () => {
        if (!fileToDelete) return;

        try {
            const result = await removeFileFromProject(project.id, fileToDelete.filename);
            onFileChange?.();

            // close dialog and then start indexing if required
            setFileToDelete(null);
            if (result.sseLocation) {
                startIndexing(result.sseLocation, project.id, "delete");
            }

            await refetch();
            addNotification("File deleted", "success");
        } catch (e) {
            console.error(`Failed to delete file ${fileToDelete.filename}:`, e);
        }
    };

    const handleToggleExpand = (filename: string) => {
        setExpandedArtifact(expandedArtifact === filename ? null : filename);
    };

    const handleFileClick = (artifact: ArtifactInfo) => {
        setSelectedArtifact(artifact);
        setShowDetailsDialog(true);
    };

    const handleEditDescription = (artifact: ArtifactInfo) => {
        setSelectedArtifact(artifact);
        setShowEditDialog(true);
    };

    const handleSaveDescription = async (description: string) => {
        if (!selectedArtifact) return;

        setIsSavingMetadata(true);
        try {
            await updateFileMetadata(project.id, selectedArtifact.filename, description);
            await refetch();
            setShowEditDialog(false);
            setSelectedArtifact(null);
        } catch (e) {
            console.error("Failed to update file description:", e);
        } finally {
            setIsSavingMetadata(false);
        }
    };

    const handleCloseDetailsDialog = () => {
        setShowDetailsDialog(false);
        setSelectedArtifact(null);
    };

    const handleCloseEditDialog = () => {
        setShowEditDialog(false);
        if (!showDetailsDialog) {
            setSelectedArtifact(null);
        }
    };

    const handleEditFromDetails = () => {
        setShowDetailsDialog(false);
        setShowEditDialog(true);
    };

    return (
        <div className="flex min-h-80 flex-1 flex-col">
            <div className="mb-3 flex items-center justify-between px-4">
                <div className="flex items-center gap-2">
                    <h3 className="text-foreground text-sm font-semibold">Knowledge</h3>
                    {!isLoading && artifacts.length > 0 && <span className="text-muted-foreground text-xs">({artifacts.length})</span>}
                </div>
            </div>

            <div className="flex min-h-0 flex-1 flex-col px-4 pb-3">
                {isLoading && (
                    <div className="flex items-center justify-center p-4">
                        <Spinner />
                    </div>
                )}

                {error && <MessageBanner variant="error" message={`Error loading files: ${error.message}`} />}

                {!isLoading && !error && (
                    <>
                        {isOwner && (filesToUpload ? null : <FileUpload name="project-files" accept="*" multiple value={filesToUpload} onChange={handleFileUploadChange} onValidate={handleValidateFileSizes} disabled={isDisabled} />)}
                        {artifacts.length > 0 && (
                            <div className="mt-4 min-h-0 flex-1 overflow-y-auto border-t">
                                {sortedArtifacts.map(artifact => {
                                    const isExpanded = expandedArtifact === artifact.filename;
                                    const expandedContent = isExpanded ? <FileDetails description={artifact.description ?? undefined} size={artifact.size} lastModified={artifact.last_modified} mimeType={artifact.mime_type} /> : undefined;

                                    return (
                                        <div key={artifact.filename} className="border-r border-l">
                                            <ArtifactBar
                                                key={artifact.filename}
                                                filename={artifact.filename}
                                                description={artifact.description || "No description provided"}
                                                mimeType={artifact.mime_type}
                                                size={artifact.size}
                                                status="completed"
                                                context="list"
                                                expandable={true}
                                                expanded={isExpanded}
                                                expandedContent={expandedContent}
                                                actions={{
                                                    onInfo: () => handleToggleExpand(artifact.filename),
                                                    onPreview: () => handleFileClick(artifact), // preview opens the details for projects instead of seeing the content
                                                    ...(isOwner &&
                                                        !isDisabled && {
                                                            onEdit: () => handleEditDescription(artifact),
                                                            onDownload: () => onDownload(artifact),
                                                            onDelete: () => handleDeleteClick(artifact),
                                                        }),
                                                }}
                                            />
                                        </div>
                                    );
                                })}
                            </div>
                        )}
                    </>
                )}
            </div>

            {isOwner && <AddProjectFilesDialog isOpen={!!filesToUpload} files={filesToUpload} onClose={handleCloseUploadDialog} onConfirm={handleConfirmUpload} isSubmitting={isSubmitting} error={uploadError} onClearError={handleClearUploadError} />}
            <FileDetailsDialog isOpen={showDetailsDialog} artifact={selectedArtifact} onClose={handleCloseDetailsDialog} onEdit={isOwner && !isDisabled ? handleEditFromDetails : undefined} />
            {isOwner && <EditFileDescriptionDialog isOpen={showEditDialog} artifact={selectedArtifact} onClose={handleCloseEditDialog} onSave={handleSaveDescription} isSaving={isSavingMetadata} />}
            {isOwner && <DeleteProjectFileDialog isOpen={!!fileToDelete} fileToDelete={fileToDelete} handleConfirmDelete={handleConfirmDelete} setFileToDelete={setFileToDelete} />}
        </div>
    );
};
