'use client';

import type React from 'react';

import { Button } from '@admin/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@admin/components/ui/card';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@admin/components/ui/dialog';
import { Input } from '@admin/components/ui/input';
import { Label } from '@admin/components/ui/label';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@admin/components/ui/select';
import axios from 'axios';
import { Upload, UploadCloud } from 'lucide-react';
// @ts-expect-error: papaparse lacks bundled types (consider adding @types/papaparse)
import Papa from 'papaparse';
import { useCallback, useState, useRef } from 'react';
import { toast } from 'sonner';

export interface CsvPayloadField { key: string; label: string }

interface CsvImportModalProps {
    isOpen: boolean;
    onClose: () => void;
    onImported?: (importItem: any) => void; // typed loosely; caller can narrow
    title: string; // e.g., 'Import Users from CSV' or 'Import Contacts from CSV'
    fields: CsvPayloadField[]; // which payload fields should be mapped
    postRouteName: string; // e.g., 'imports.users' | 'imports.contacts'
    limitHeaderOptionsToFields?: boolean; // if true, only suggest headers matching each field's aliases
}

interface CsvData {
    headers: string[];
    rows: string[][];
}

interface ColumnMapping {
    [payloadField: string]: string;
}

export function CsvImportModal({ isOpen, onClose, onImported, title, fields, postRouteName, limitHeaderOptionsToFields = false }: CsvImportModalProps) {
    const [step, setStep] = useState<'upload' | 'mapping' | 'preview'>('upload');
    const [csvData, setCsvData] = useState<CsvData | null>(null);
    const [columnMapping, setColumnMapping] = useState<ColumnMapping>({});
    const [selectedFile, setSelectedFile] = useState<File | null>(null);
    const fileInputRef = useRef<HTMLInputElement | null>(null);

    const processFile = useCallback(
        (file: File) => {
            if (file.type !== 'text/csv' && !file.name.endsWith('.csv')) {
                toast.error("'Invalid file type'", {
                    description: 'Please upload a CSV file',
                });
                return;
            }

            setSelectedFile(file);
            Papa.parse<string[]>(file, {
                complete: (results: Papa.ParseResult<string[]>) => {
                    if (results.errors.length > 0) {
                        toast.error('CSV parsing error', {
                            description: 'There was an error parsing your CSV file',
                        });
                        return;
                    }

                    const headers = results.data[0] as string[];
                    const rows = results.data.slice(1) as string[][];

                    setCsvData({ headers, rows });
                    setStep('mapping');

                    // Auto-map columns based on common names
                    const autoMapping: ColumnMapping = {};

                    // Common alias dictionary to improve auto-detection
                    const ALIASES: Record<string, string[]> = {
                        name: ['name', 'full name', 'contact name'],
                        email: ['email', 'e-mail', 'mail'],
                        phone: ['phone', 'phone number', 'mobile', 'cell', 'cellphone', 'contact number', 'telephone', 'tel'],
                        notes: ['notes', 'note', 'remarks', 'remark', 'comments', 'comment', 'description', 'desc'],
                        // Users
                        first_name: ['first_name', 'first name', 'firstname', 'given name'],
                        last_name: ['last_name', 'last name', 'lastname', 'surname', 'family name'],
                        role: ['role', 'user role', 'group'],
                    };

                    headers.forEach((header) => {
                        const lowerHeader = header.toLowerCase().trim();
                        fields.forEach((f) => {
                            const key = f.key.toLowerCase();
                            const label = f.label.toLowerCase().trim();
                            const labelCompact = label.replace(/\s+/g, '');
                            const headerCompact = lowerHeader.replace(/\s+/g, '');
                            const aliases = ALIASES[key] || [];

                            const match =
                                lowerHeader === key ||
                                lowerHeader === label ||
                                lowerHeader.includes(label) ||
                                headerCompact === labelCompact ||
                                aliases.some((a) => lowerHeader === a || headerCompact === a.replace(/\s+/g, ''));

                            if (match && !autoMapping[f.key]) {
                                autoMapping[f.key] = header;
                            }
                        });
                    });
                    setColumnMapping(autoMapping);
                },
                header: false,
                skipEmptyLines: true,
            });
        },
        [toast, fields],
    );

    const handleFileUpload = useCallback(
        (event: React.ChangeEvent<HTMLInputElement>) => {
            const file = event.target.files?.[0];
            if (!file) return;
            processFile(file);
        },
        [processFile],
    );

    const handleMappingChange = (payloadField: string, csvColumn: string) => {
        setColumnMapping((prev) => ({
            ...prev,
            [payloadField]: csvColumn,
        }));
    };

    const handleImport = async () => {
        if (!csvData) return;

        // Build FormData payload
        const form = new FormData();
        if (!selectedFile) {
            toast.error('No file selected', { description: 'Please choose a CSV file again.' });
            return;
        }
        form.append('file', selectedFile);

        // Append column_mapping as keys like column_mapping[First Name]: first_name
        Object.keys(columnMapping).forEach((payloadKey) => {
            const csvColumn = columnMapping[payloadKey];
            if (!csvColumn || csvColumn === 'none') return;
            form.append(`column_mapping[${csvColumn}]`, payloadKey);
        });

        try {
            const postUrl = (typeof route !== 'undefined') ? route(postRouteName) : `/imports/${postRouteName.split('.').pop()}`;
            const response = await axios.post(postUrl, form, {
                headers: {
                    'Content-Type': 'multipart/form-data',
                },
            });
            toast.success(response.data.message || 'Import started');
            if (onImported && response.data.import) {
                onImported(response.data.import.data ?? response.data.import); // resource or raw
            }

            // Reset modal state on success
            setStep('upload');
            setCsvData(null);
            setColumnMapping({});
            onClose();
        } catch (error: any) {
            // Collect possible validation errors
            const errors = error?.response?.data?.errors;
            let description = error?.response?.data?.message || error?.message || 'Import failed';
            if (errors && typeof errors === 'object') {
                const list = Object.entries(errors)
                    .flatMap(([, msgs]: any) => (Array.isArray(msgs) ? msgs : [msgs]))
                    .join('; ');
                if (list) description = list;
            }
            const status = error?.response?.status;
            toast.error(`Import failed${status ? ' (' + status + ')' : ''}`, { description });
        }
    };

    const handleClose = () => {
        setStep('upload');
        setCsvData(null);
        setColumnMapping({});
        setSelectedFile(null);
        onClose();
    };

    // drag & drop handlers (upload step only)
    const handleDrop = (e: React.DragEvent<HTMLDivElement>) => {
        e.preventDefault();
        if (step !== 'upload') return;
        const file = e.dataTransfer.files?.[0];
        if (file) processFile(file);
    };
    const preventDefault = (e: React.DragEvent<HTMLDivElement>) => {
        if (step === 'upload') e.preventDefault();
    };

    const triggerFileDialog = () => {
        if (step === 'upload') fileInputRef.current?.click();
    };

    return (
    <Dialog open={isOpen} onOpenChange={handleClose}>
            <DialogContent className="max-h-[80vh] w-full max-w-lg overflow-y-auto sm:max-w-2xl lg:max-w-4xl">
                <DialogHeader>
                    <DialogTitle className="flex items-center gap-2">
                        <Upload className="size-5" />
            {title}
                    </DialogTitle>
                </DialogHeader>

                {step === 'upload' && (
                    <div
                        className="relative flex min-h-72 cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed border-border p-8 text-center transition-colors hover:bg-muted/40 focus-visible:outline-none"
                        role="button"
                        tabIndex={0}
                        onClick={triggerFileDialog}
                        onKeyDown={(e) => {
                            if (e.key === 'Enter' || e.key === ' ') {
                                e.preventDefault();
                                triggerFileDialog();
                            }
                        }}
                        onDrop={handleDrop}
                        onDragOver={preventDefault}
                        onDragEnter={preventDefault}
                    >
                        <UploadCloud className="mx-auto mb-4 size-12 text-muted-foreground" />
                        <div className="space-y-2">
                            <p className="text-lg font-medium">Click or Drag & Drop to Upload CSV</p>
                            <p className="text-sm text-muted-foreground">Entire area is interactive. Supported format: .csv</p>
                        </div>
                        <Input
                            ref={fileInputRef}
                            id="csv-upload"
                            type="file"
                            accept=".csv"
                            onChange={handleFileUpload}
                            className="hidden"
                        />
                    </div>
                )}

                {step === 'mapping' && csvData && (
                    <div className="space-y-6">
                        <Card>
                            <CardHeader className="px-2 py-2 pb-3">
                                <CardTitle>Column Mapping</CardTitle>
                                <p className="text-sm text-muted-foreground">Map CSV columns to the required payload fields</p>
                            </CardHeader>
                            <CardContent className="space-y-4">
                                {fields.map((field) => (
                                    <div key={field.key} className="flex items-center gap-4">
                                        <div className="flex-1">
                                            <Label className="text-sm font-medium">{field.label}</Label>
                                        </div>
                                        <div className="flex-1">
                                            <Select
                                                value={columnMapping[field.key] || 'none'}
                                                onValueChange={(value) => handleMappingChange(field.key, value)}
                                            >
                                                <SelectTrigger>
                                                    <SelectValue placeholder="Select CSV column..." />
                                                </SelectTrigger>
                                                <SelectContent>
                                                    <SelectItem value="none">-- Skip this field --</SelectItem>
                                                    {(csvData.headers || [])
                                                        .filter((header) => {
                                                            if (!limitHeaderOptionsToFields) return true;
                                                            const h = header.toLowerCase().trim();
                                                            const aliases: Record<string, string[]> = {
                                                                name: ['name', 'full name', 'contact name'],
                                                                email: ['email', 'e-mail', 'mail'],
                                                                phone: ['phone', 'phone number', 'mobile', 'cell', 'cellphone', 'contact number', 'telephone', 'tel'],
                                                                notes: ['notes', 'note', 'remarks', 'remark', 'comments', 'comment', 'description', 'desc'],
                                                                first_name: ['first_name', 'first name', 'firstname', 'given name'],
                                                                last_name: ['last_name', 'last name', 'lastname', 'surname', 'family name'],
                                                                role: ['role', 'user role', 'group'],
                                                            };
                                                            const key = field.key.toLowerCase();
                                                            const list = aliases[key] || [key];
                                                            const compact = (s: string) => s.replace(/\s+/g, '');
                                                            return list.some((a) => h === a || compact(h) === compact(a) || h.includes(a));
                                                        })
                                                        .map((header) => (
                                                            <SelectItem key={header} value={header}>
                                                                {header}
                                                            </SelectItem>
                                                        ))}
                                                </SelectContent>
                                            </Select>
                                        </div>
                                    </div>
                                ))}
                            </CardContent>
                        </Card>

                        <div className="flex justify-between">
                            <Button variant="outline" onClick={() => setStep('upload')}>
                                Back
                            </Button>
                            <Button onClick={handleImport}>Start Import</Button>
                        </div>
                    </div>
                )}
                {/* preview step removed - import is triggered directly from mapping */}
            </DialogContent>
        </Dialog>
    );
}
