import { router, usePage } from '@inertiajs/react';
import {
    CheckCircle2,
    ExternalLink,
    FileUp,
    Image as ImageIcon,
    Link as LinkIcon,
    Pencil,
    Trash2,
} from 'lucide-react';
import { useState } from 'react';
import { toast } from 'sonner';

import { ConfirmDeleteDialog } from '@/components/ConfirmDeleteDialog';
import { ProofFileInput } from '@/components/tasks/ProofFileInput';
import { Button } from '@/components/ui/button';
import {
    Dialog,
    DialogContent,
    DialogDescription,
    DialogHeader,
    DialogTitle,
} from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import {
    formatProofLabel,
    invalidProofFileMessage,
    isAllowedProofFile,
    maxProofFileSizeBytes,
    maxProofFileSizeLabel,
    maxRawImageFileSizeLabel,
    optimizeImageProofFile,
    proofFileAccept,
} from '@/lib/task-proof-utils';
import type { Auth } from '@/types';
import type { Task } from '@/types/task';

interface TaskProofSectionProps {
    task: Task;
    isAssignee?: boolean;
}

const proofTypeLabels: Record<string, string> = {
    file: 'File / Document',
    image: 'Image / Screenshot',
    link: 'Link / URL',
};

const proofRoute = (proofId: number | string) => `/tasks/proofs/${proofId}`;
const storeProofRoute = (taskCode: string) => `/tasks/${taskCode}/proofs`;

const firstErrorMessage = (errors: Record<string, string>) =>
    Object.values(errors)[0] || 'Failed to submit completion proof';

export function TaskProofSection({
    task,
    isAssignee = false,
}: TaskProofSectionProps) {
    const { auth } = usePage<Auth>().props;
    const currentUserId = auth?.user?.id;
    const [proofFile, setProofFile] = useState<File | null>(null);
    const [proofLink, setProofLink] = useState('');
    const [editingProofId, setEditingProofId] = useState<
        number | string | null
    >(null);
    const [editProofFile, setEditProofFile] = useState<File | null>(null);
    const [editProofLink, setEditProofLink] = useState('');
    const [isSubmittingProof, setIsSubmittingProof] = useState(false);
    const [isUpdatingProof, setIsUpdatingProof] = useState(false);
    const [deletingProofId, setDeletingProofId] = useState<
        number | string | null
    >(null);
    const [pendingDeleteProofId, setPendingDeleteProofId] = useState<
        number | string | null
    >(null);
    const [isOptimizingImage, setIsOptimizingImage] = useState(false);
    const [previewImageProof, setPreviewImageProof] = useState<{
        url: string;
        label: string;
    } | null>(null);

    if (!task.requiredProofType || task.requiredProofType === 'none') {
        return (
            <section className="max-w-full space-y-3 overflow-hidden rounded-xl border border-border bg-muted/20 p-3">
                <div className="flex min-w-0 items-start gap-2">
                    <div className="mt-0.5 rounded-full bg-muted p-1 text-muted-foreground">
                        <CheckCircle2 className="h-3.5 w-3.5" />
                    </div>
                    <div className="min-w-0 flex-1">
                        <p className="text-xs font-semibold text-foreground">
                            Completion Proof Optional
                        </p>
                        <p className="max-w-full text-[11px] leading-relaxed wrap-break-word text-muted-foreground">
                            You do not need to attach completion proof to finish
                            this task.
                        </p>
                    </div>
                </div>
            </section>
        );
    }

    const proofs = task.proofs || [];

    // Cermin dari TaskProofController::proofIsLocked() dan TaskPolicy::uploadProof():
    // bukti hanya terbuka selama task dikerjakan. Riwayat review sengaja tidak
    // ikut dihitung — penolakan mengembalikan task ke in_progress, dan status itu
    // sendiri yang membuka kuncinya.
    const proofIsLocked = task.status !== 'in_progress';

    const proofLockedMessage: Record<string, string> = {
        review: 'This proof is under review and cannot be changed until a supervisor returns the task for revision.',
        completed: 'This proof has been accepted and can no longer be changed.',
        waiting:
            'Start working on this task before uploading your completion proof.',
    };

    const proofTypeLabel =
        proofTypeLabels[task.requiredProofType] || task.requiredProofType;

    const validateSelectedFile = (file: File | null) => {
        if (!file) {
            toast.error('Select a proof file first');

            return false;
        }

        if (task.requiredProofType !== 'image') {
            if (file.size > maxProofFileSizeBytes) {
                toast.error(
                    `Ukuran file terlalu besar. Maksimal ${maxProofFileSizeLabel}.`,
                );

                return false;
            }

            if (!isAllowedProofFile(file.name)) {
                toast.error(invalidProofFileMessage);

                return false;
            }
        }

        return true;
    };

    const appendProofPayload = (
        formData: FormData,
        file: File | null,
        link: string,
    ) => {
        if (task.requiredProofType === 'link') {
            if (!link.trim()) {
                toast.error('Enter a proof link first');

                return false;
            }

            formData.append('link', link.trim());

            return true;
        }

        if (!validateSelectedFile(file)) {
            return false;
        }

        formData.append('file', file!);

        return true;
    };

    const handleSubmitProof = (e: React.FormEvent) => {
        e.preventDefault();

        const formData = new FormData();

        if (!appendProofPayload(formData, proofFile, proofLink)) {
            return;
        }

        router.post(storeProofRoute(task.code), formData, {
            forceFormData: true,
            preserveScroll: true,
            onBefore: () => setIsSubmittingProof(true),
            onSuccess: () => {
                setProofFile(null);
                setProofLink('');
                toast.success('Completion proof submitted');
            },
            onError: (errors) => {
                toast.error(firstErrorMessage(errors));
            },
            onFinish: () => setIsSubmittingProof(false),
        });
    };

    const handleUpdateProof = (proofId: number | string) => {
        const formData = new FormData();

        if (!appendProofPayload(formData, editProofFile, editProofLink)) {
            return;
        }

        formData.append('_method', 'put');

        router.post(proofRoute(proofId), formData, {
            forceFormData: true,
            preserveScroll: true,
            onBefore: () => setIsUpdatingProof(true),
            onSuccess: () => {
                setEditingProofId(null);
                setEditProofFile(null);
                setEditProofLink('');
                toast.success('Completion proof updated');
            },
            onError: (errors) => {
                toast.error(firstErrorMessage(errors));
            },
            onFinish: () => setIsUpdatingProof(false),
        });
    };

    const confirmDeleteProof = () => {
        if (pendingDeleteProofId == null) {
            return;
        }

        const proofId = pendingDeleteProofId;
        router.delete(proofRoute(proofId), {
            preserveScroll: true,
            onBefore: () => setDeletingProofId(proofId),
            onSuccess: () => {
                toast.success('Completion proof deleted');
                setPendingDeleteProofId(null);
            },
            onError: () => {
                toast.error('Failed to delete completion proof');
            },
            onFinish: () => setDeletingProofId(null),
        });
    };

    /**
     * Validasi + proses file mentah dari dropzone, lalu set ke state tujuan.
     * Untuk tipe image: pastikan MIME image, lalu optimasi ke webp.
     * Untuk tipe file: cek batas ukuran & ekstensi dokumen yang diizinkan.
     */
    const handleProofFileSelect = async (
        selectedFile: File | null,
        onFileReady: (file: File | null) => void,
    ) => {
        if (!selectedFile) {
            onFileReady(null);

            return;
        }

        if (task.requiredProofType === 'image') {
            if (!selectedFile.type.startsWith('image/')) {
                toast.error('Proof must be a valid image.');
                onFileReady(null);

                return;
            }

            setIsOptimizingImage(true);

            try {
                onFileReady(await optimizeImageProofFile(selectedFile));
            } catch (error) {
                toast.error(
                    error instanceof Error
                        ? error.message
                        : 'Failed to process the image.',
                );
                onFileReady(null);
            } finally {
                setIsOptimizingImage(false);
            }

            return;
        }

        if (selectedFile.size > maxProofFileSizeBytes) {
            toast.error(
                `Ukuran file terlalu besar. Maksimal ${maxProofFileSizeLabel}.`,
            );
            onFileReady(null);

            return;
        }

        if (!isAllowedProofFile(selectedFile.name)) {
            toast.error(invalidProofFileMessage);
            onFileReady(null);

            return;
        }

        onFileReady(selectedFile);
    };

    return (
        <>
            <section className="w-full max-w-full space-y-3 overflow-hidden rounded-xl border border-amber-200 bg-amber-50/30 p-3 dark:border-amber-900/30 dark:bg-amber-900/10">
                <div className="flex min-w-0 items-start gap-2">
                    <div className="mt-0.5 shrink-0 rounded-full bg-amber-100 p-1 text-amber-600 dark:bg-amber-900 dark:text-amber-400">
                        {proofs.length > 0 ? (
                            <CheckCircle2 className="h-3.5 w-3.5" />
                        ) : (
                            <FileUp className="h-3.5 w-3.5" />
                        )}
                    </div>
                    <div className="min-w-0 flex-1">
                        <p className="text-xs font-semibold text-amber-900 dark:text-amber-200">
                            Completion Proof Required
                        </p>
                        <p className="max-w-full text-[11px] leading-relaxed text-amber-700 dark:text-amber-400/80">
                            You must attach{' '}
                            <span className="font-bold underline underline-offset-2">
                                {proofTypeLabel}
                            </span>{' '}
                            to finish this task.
                        </p>
                        {task.requiredProofType !== 'link' && (
                            <p className="mt-1 text-[11px] text-amber-700/80 dark:text-amber-400/70">
                                {task.requiredProofType === 'image'
                                    ? `Maximum image size ${maxRawImageFileSizeLabel}.`
                                    : `Maximum file size ${maxProofFileSizeLabel}.`}
                            </p>
                        )}
                    </div>
                </div>

                {proofs.length > 0 && (
                    <div className="w-full max-w-full space-y-2 overflow-hidden">
                        {proofs.map((proof) => {
                            const proofUrl = proof.file_url || undefined;
                            const proofLabel = formatProofLabel(
                                proof.file,
                                task.requiredProofType,
                                proof.original_name,
                            );
                            const isOwnProof =
                                String(proof.user_id) === String(currentUserId);
                            const isEditing =
                                editingProofId !== null &&
                                String(editingProofId) === String(proof.id);
                            const isImageProof =
                                task.requiredProofType === 'image' &&
                                Boolean(proofUrl);

                            return (
                                <div key={proof.id} className="space-y-2">
                                    <div className="flex max-w-full min-w-0 items-center gap-1 overflow-hidden rounded-lg border border-amber-200/80 bg-background/80 px-3 py-2 text-xs font-medium text-foreground transition hover:bg-background dark:border-amber-900/40">
                                        {isImageProof ? (
                                            <button
                                                type="button"
                                                onClick={() =>
                                                    setPreviewImageProof({
                                                        url: proofUrl!,
                                                        label: proofLabel,
                                                    })
                                                }
                                                className="flex min-w-0 flex-1 cursor-pointer items-center gap-2 overflow-hidden text-left decoration-amber-700/30 underline-offset-2 transition-colors hover:text-amber-700 hover:underline dark:hover:text-amber-300 dark:hover:decoration-amber-300/30"
                                                title={proofLabel}
                                            >
                                                <ImageIcon className="h-3.5 w-3.5 shrink-0 text-amber-600" />
                                                <span className="min-w-0 flex-1 truncate">
                                                    {proofLabel}
                                                </span>
                                                <span className="ml-auto shrink-0 text-[11px] text-muted-foreground transition-colors hover:text-amber-600 dark:hover:text-amber-400">
                                                    View
                                                </span>
                                            </button>
                                        ) : (
                                            <a
                                                href={proofUrl || '#'}
                                                target="_blank"
                                                rel="noreferrer"
                                                className="flex min-w-0 flex-1 cursor-pointer items-center gap-2 overflow-hidden decoration-amber-700/30 underline-offset-2 transition-colors hover:text-amber-700 hover:underline dark:hover:text-amber-300 dark:hover:decoration-amber-300/30"
                                                title={proofUrl}
                                            >
                                                {task.requiredProofType ===
                                                'link' ? (
                                                    <LinkIcon className="h-3.5 w-3.5 shrink-0 text-amber-600" />
                                                ) : (
                                                    <FileUp className="h-3.5 w-3.5 shrink-0 text-amber-600" />
                                                )}
                                                <span className="min-w-0 flex-1 truncate">
                                                    {proofLabel}
                                                </span>
                                                <ExternalLink className="ml-auto h-3.5 w-3.5 shrink-0 text-muted-foreground transition-colors hover:text-amber-600 dark:hover:text-amber-400" />
                                            </a>
                                        )}

                                        {isAssignee &&
                                            isOwnProof &&
                                            !proofIsLocked && (
                                                <div className="ml-2 flex shrink-0 items-center gap-1 border-l pl-2">
                                                    <Button
                                                        type="button"
                                                        variant="ghost"
                                                        size="icon"
                                                        className="h-6 w-6 text-muted-foreground"
                                                        onClick={() => {
                                                            setEditingProofId(
                                                                proof.id,
                                                            );
                                                            setEditProofLink(
                                                                task.requiredProofType ===
                                                                    'link'
                                                                    ? proof.file ||
                                                                          ''
                                                                    : '',
                                                            );
                                                            setEditProofFile(
                                                                null,
                                                            );
                                                        }}
                                                    >
                                                        <Pencil className="h-3.5 w-3.5" />
                                                    </Button>
                                                    <Button
                                                        type="button"
                                                        variant="ghost"
                                                        size="icon"
                                                        className="h-6 w-6 text-muted-foreground hover:text-red-600"
                                                        disabled={
                                                            deletingProofId ===
                                                            proof.id
                                                        }
                                                        onClick={() =>
                                                            setPendingDeleteProofId(
                                                                proof.id,
                                                            )
                                                        }
                                                    >
                                                        <Trash2 className="h-3.5 w-3.5" />
                                                    </Button>
                                                </div>
                                            )}
                                    </div>

                                    {isEditing && (
                                        <div className="w-full max-w-full rounded-lg border border-amber-200/80 bg-background/80 p-3 dark:border-amber-900/40">
                                            <div className="w-full max-w-full space-y-2">
                                                {task.requiredProofType ===
                                                'link' ? (
                                                    <Input
                                                        type="url"
                                                        value={editProofLink}
                                                        onChange={(e) =>
                                                            setEditProofLink(
                                                                e.target.value,
                                                            )
                                                        }
                                                        placeholder="https://..."
                                                        className="h-9 w-full bg-background"
                                                    />
                                                ) : (
                                                    <ProofFileInput
                                                        file={editProofFile}
                                                        onSelect={(
                                                            selectedFile,
                                                        ) =>
                                                            handleProofFileSelect(
                                                                selectedFile,
                                                                setEditProofFile,
                                                            )
                                                        }
                                                        accept={
                                                            task.requiredProofType ===
                                                            'image'
                                                                ? 'image/*'
                                                                : proofFileAccept
                                                        }
                                                        variant={
                                                            task.requiredProofType ===
                                                            'image'
                                                                ? 'image'
                                                                : 'file'
                                                        }
                                                        isProcessing={
                                                            isOptimizingImage
                                                        }
                                                        hint={
                                                            task.requiredProofType ===
                                                            'image'
                                                                ? `Image max. ${maxRawImageFileSizeLabel}`
                                                                : `Document max. ${maxProofFileSizeLabel}`
                                                        }
                                                        disabled={
                                                            isUpdatingProof
                                                        }
                                                    />
                                                )}
                                                <div className="flex justify-end gap-2">
                                                    <Button
                                                        type="button"
                                                        variant="ghost"
                                                        size="sm"
                                                        className="h-8 text-xs"
                                                        onClick={() => {
                                                            setEditingProofId(
                                                                null,
                                                            );
                                                            setEditProofFile(
                                                                null,
                                                            );
                                                            setEditProofLink(
                                                                '',
                                                            );
                                                        }}
                                                    >
                                                        Cancel
                                                    </Button>
                                                    <Button
                                                        type="button"
                                                        size="sm"
                                                        className="h-8 text-xs"
                                                        disabled={
                                                            isUpdatingProof ||
                                                            isOptimizingImage
                                                        }
                                                        onClick={() =>
                                                            handleUpdateProof(
                                                                proof.id,
                                                            )
                                                        }
                                                    >
                                                        {isUpdatingProof
                                                            ? 'Saving...'
                                                            : 'Save'}
                                                    </Button>
                                                </div>
                                            </div>
                                        </div>
                                    )}
                                </div>
                            );
                        })}
                    </div>
                )}

                {isAssignee && proofIsLocked && (
                    <p className="rounded-lg border border-dashed border-amber-300 bg-background/60 px-3 py-2 text-[11px] leading-relaxed text-amber-800 dark:border-amber-900/60 dark:text-amber-300">
                        {proofLockedMessage[task.status] ??
                            'Completion proof can only be changed while the task is in progress.'}
                    </p>
                )}

                {isAssignee && !proofIsLocked && (
                    <form
                        onSubmit={handleSubmitProof}
                        className="w-full max-w-full space-y-2"
                    >
                        {task.requiredProofType === 'link' ? (
                            <div className="w-full max-w-full space-y-1.5">
                                <label
                                    htmlFor={`proof-link-${task.id}`}
                                    className="text-[11px] font-semibold text-amber-900 dark:text-amber-200"
                                >
                                    Link Bukti
                                </label>
                                <Input
                                    id={`proof-link-${task.id}`}
                                    name="link"
                                    type="url"
                                    value={proofLink}
                                    onChange={(e) =>
                                        setProofLink(e.target.value)
                                    }
                                    placeholder="https://..."
                                    className="h-9 w-full bg-background"
                                    required
                                />
                            </div>
                        ) : (
                            <div className="w-full max-w-full space-y-1.5">
                                <label className="text-[11px] font-semibold text-amber-900 dark:text-amber-200">
                                    File Bukti
                                </label>
                                <ProofFileInput
                                    file={proofFile}
                                    onSelect={(selectedFile) =>
                                        handleProofFileSelect(
                                            selectedFile,
                                            setProofFile,
                                        )
                                    }
                                    accept={
                                        task.requiredProofType === 'image'
                                            ? 'image/*'
                                            : proofFileAccept
                                    }
                                    variant={
                                        task.requiredProofType === 'image'
                                            ? 'image'
                                            : 'file'
                                    }
                                    isProcessing={isOptimizingImage}
                                    hint={
                                        task.requiredProofType === 'image'
                                            ? `Image max. ${maxRawImageFileSizeLabel}`
                                            : `Document max. ${maxProofFileSizeLabel}`
                                    }
                                    disabled={isSubmittingProof}
                                />
                            </div>
                        )}

                        <div className="flex justify-end">
                            <Button
                                type="submit"
                                size="sm"
                                className="h-8 text-xs"
                                disabled={
                                    isSubmittingProof || isOptimizingImage
                                }
                            >
                                {isOptimizingImage
                                    ? 'Processing...'
                                    : isSubmittingProof
                                      ? 'Sending...'
                                      : 'Submit Proof'}
                            </Button>
                        </div>
                    </form>
                )}
            </section>

            <Dialog
                open={Boolean(previewImageProof)}
                onOpenChange={(isOpen) => {
                    if (!isOpen) {
                        setPreviewImageProof(null);
                    }
                }}
            >
                <DialogContent className="w-fit max-w-[calc(100vw-2rem)] border-0 bg-transparent p-0 shadow-none sm:max-w-[calc(100vw-2rem)]">
                    <DialogHeader className="sr-only">
                        <DialogTitle className="text-base">
                            Bukti Penyelesaian
                        </DialogTitle>
                        <DialogDescription className="truncate">
                            {previewImageProof?.label}
                        </DialogDescription>
                    </DialogHeader>
                    {previewImageProof && (
                        <div className="overflow-hidden rounded-lg bg-background shadow-lg">
                            <img
                                src={previewImageProof.url}
                                alt={previewImageProof.label}
                                className="block h-auto max-h-[85vh] w-auto max-w-[calc(100vw-2rem)] object-contain"
                            />
                        </div>
                    )}
                </DialogContent>
            </Dialog>

            <ConfirmDeleteDialog
                open={pendingDeleteProofId != null}
                onOpenChange={(next) => {
                    if (!next) {
                        setPendingDeleteProofId(null);
                    }
                }}
                onConfirm={confirmDeleteProof}
                processing={deletingProofId != null}
                variant="center"
                icon={Trash2}
                title="Delete Proof?"
                description="This completion proof will be permanently removed and cannot be restored."
                confirmLabel="Delete Proof"
                cancelLabel="Cancel"
                processingLabel="Deleting..."
            />
        </>
    );
}
