import { Button } from '@admin/components/ui/button';
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, { AxiosError } from 'axios';
import { ArrowLeft, ArrowRight, FileText, Upload } from 'lucide-react';
import { useCallback, useState, useRef } from 'react';
import { toast } from 'sonner';

export interface ContactCsvImportModalProps {
    isOpen: boolean;
    onClose: () => void;
    onImported?: (importedData: any) => void;
}

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

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

interface ContactData {
    name: string;
    email: string;
    phone: string;
    notes?: string;
}

const PAYLOAD_FIELDS = [
    { key: 'name', label: 'Name' },
    { key: 'email', label: 'Email' },
    { key: 'phone', label: 'Phone' },
    { key: 'notes', label: 'Note' },
];

export function ContactCsvImportModal({ isOpen, onClose, onImported }: ContactCsvImportModalProps) {
    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;
            }

            const reader = new FileReader();
            reader.onload = (e) => {
                const text = e.target?.result as string;
                const lines = text.split('\n').filter((line) => line.trim());
                if (lines.length < 2) {
                    toast.error('Invalid CSV', {
                        description: 'CSV must have at least a header row and one data row',
                    });
                    return;
                }

                const headers = lines[0].split(',').map((h) => h.trim().replace(/"/g, ''));
                const rows = lines
                    .slice(1)
                    .map((line) => line.split(',').map((cell) => cell.trim().replace(/"/g, '')));

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

            reader.onerror = () => {
                toast.error('Error reading file', {
                    description: 'Failed to read the CSV file',
                });
            };

            reader.readAsText(file);
        },
        [],
    );

    const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        const file = e.target.files?.[0];
        if (file) {
            setSelectedFile(file);
            processFile(file);
        }
    };

    const handleNext = () => {
        if (step === 'mapping') {
            setStep('preview');
        }
    };

    const handleBack = () => {
        if (step === 'mapping') {
            setStep('upload');
        } else if (step === 'preview') {
            setStep('mapping');
        }
    };

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

        try {
            const formData = new FormData();
            formData.append('file', selectedFile);
            formData.append('column_mapping', JSON.stringify(columnMapping));

            const postUrl = (typeof route !== 'undefined') ? route('imports.contacts') : '/imports/contacts';
            const response = await axios.post(postUrl, formData, {
                headers: {
                    'Content-Type': 'multipart/form-data',
                },
            });

            toast.success('Import started', {
                description: 'Your contact import has been queued for processing',
            });

            if (onImported) {
                onImported(response.data.import);
            }

            // Reset modal state
            setStep('upload');
            setCsvData(null);
            setColumnMapping({});
            setSelectedFile(null);
            onClose();
        } catch (error) {
            const axiosError = error as AxiosError;
            if (axiosError.response?.status === 422) {
                const errors = (axiosError.response.data as any)?.errors;
                if (errors) {
                    Object.values(errors).forEach((errorArray: any) => {
                        if (Array.isArray(errorArray)) {
                            errorArray.forEach((err) => toast.error('Validation Error', { description: err }));
                        }
                    });
                } else {
                    toast.error('Validation failed', {
                        description: 'Please check your file and column mappings',
                    });
                }
            } else {
                toast.error('Import failed', {
                    description: 'An error occurred while starting the import',
                });
            }
        }
    };

    const getMappedData = (): ContactData[] => {
        if (!csvData) return [];

        return csvData.rows.slice(0, 5).map((row) => {
            const mappedRow: any = {};
            Object.entries(columnMapping).forEach(([csvCol, payloadField]) => {
                const colIndex = csvData.headers.indexOf(csvCol);
                if (colIndex !== -1) {
                    mappedRow[payloadField] = row[colIndex] || '';
                }
            });
            return mappedRow as ContactData;
        });
    };

    const resetModal = () => {
        setStep('upload');
        setCsvData(null);
        setColumnMapping({});
        setSelectedFile(null);
        if (fileInputRef.current) {
            fileInputRef.current.value = '';
        }
    };

    const handleClose = () => {
        resetModal();
        onClose();
    };

    return (
        <Dialog open={isOpen} onOpenChange={handleClose}>
            <DialogContent className="max-w-4xl max-h-[80vh] overflow-y-auto">
                <DialogHeader>
                    <DialogTitle className="flex items-center gap-2">
                        <FileText className="size-5" />
                        Import Contacts from CSV
                    </DialogTitle>
                </DialogHeader>

                {step === 'upload' && (
                    <div className="space-y-4">
                        <div className="text-sm text-muted-foreground">
                            Upload a CSV file containing contact information. The first row should contain column headers.
                        </div>

                        <div className="border-2 border-dashed border-muted-foreground/25 rounded-lg p-8 text-center">
                            <Upload className="size-12 mx-auto mb-4 text-muted-foreground" />
                            <div className="space-y-2">
                                <Button onClick={() => fileInputRef.current?.click()} variant="outline">
                                    Choose CSV File
                                </Button>
                                <div className="text-sm text-muted-foreground">
                                    {selectedFile ? selectedFile.name : 'No file selected'}
                                </div>
                            </div>
                            <input
                                ref={fileInputRef}
                                type="file"
                                accept=".csv"
                                onChange={handleFileChange}
                                className="hidden"
                            />
                        </div>

                            <div className="text-xs text-muted-foreground space-y-1">
                            <div className="font-medium">Supported columns:</div>
                            <div>Name, Email, Phone, Note</div>
                            <div className="mt-2 font-medium">Requirements:</div>
                            <div>• Name is required</div>
                            <div>• Email format will be validated if provided</div>
                        </div>
                    </div>
                )}

                {step === 'mapping' && csvData && (
                    <div className="space-y-4">
                        <div className="flex items-center justify-between">
                            <h3 className="text-lg font-medium">Map CSV Columns</h3>
                            <div className="text-sm text-muted-foreground">
                                Found {csvData.rows.length} rows
                            </div>
                        </div>

                        <div className="grid gap-4">
                            {PAYLOAD_FIELDS.map((field) => (
                                <div key={field.key} className="grid grid-cols-2 items-center gap-4">
                                    <Label className="text-right">{field.label}:</Label>
                                    <Select
                                        value={
                                            Object.entries(columnMapping).find(
                                                ([, value]) => value === field.key,
                                            )?.[0] || ''
                                        }
                                        onValueChange={(value) =>
                                            setColumnMapping((prev) => {
                                                const newMapping = { ...prev };
                                                // Remove any existing mapping for this field
                                                Object.entries(newMapping).forEach(([key, val]) => {
                                                    if (val === field.key) {
                                                        delete newMapping[key];
                                                    }
                                                });
                                                // Add new mapping if value is not empty
                                                if (value) {
                                                    newMapping[value] = field.key;
                                                }
                                                return newMapping;
                                            })
                                        }
                                    >
                                        <SelectTrigger>
                                            <SelectValue placeholder="Select CSV column" />
                                        </SelectTrigger>
                                        <SelectContent>
                                            <SelectItem value="">-- Not mapped --</SelectItem>
                                            {csvData.headers.map((header) => (
                                                <SelectItem key={header} value={header}>
                                                    {header}
                                                </SelectItem>
                                            ))}
                                        </SelectContent>
                                    </Select>
                                </div>
                            ))}
                        </div>

                        <div className="flex justify-between">
                            <Button variant="outline" onClick={handleBack}>
                                <ArrowLeft className="size-4 mr-2" />
                                Back
                            </Button>
                            <Button onClick={handleNext} disabled={Object.keys(columnMapping).length === 0}>
                                Next
                                <ArrowRight className="size-4 ml-2" />
                            </Button>
                        </div>
                    </div>
                )}

                {step === 'preview' && (
                    <div className="space-y-4">
                        <div className="flex items-center justify-between">
                            <h3 className="text-lg font-medium">Preview Import Data</h3>
                            <div className="text-sm text-muted-foreground">
                                Showing first 5 rows
                            </div>
                        </div>

                        <div className="border rounded-lg overflow-hidden">
                            <div className="overflow-x-auto">
                                <table className="w-full">
                                    <thead className="bg-muted">
                                        <tr>
                                            {PAYLOAD_FIELDS.map((field) => (
                                                <th key={field.key} className="px-3 py-2 text-left text-sm font-medium">
                                                    {field.label}
                                                </th>
                                            ))}
                                        </tr>
                                    </thead>
                                    <tbody>
                                        {getMappedData().map((row, index) => (
                                            <tr key={index} className="border-t">
                                                {PAYLOAD_FIELDS.map((field) => (
                                                    <td key={field.key} className="px-3 py-2 text-sm">
                                                        {(row as any)[field.key] || '--'}
                                                    </td>
                                                ))}
                                            </tr>
                                        ))}
                                    </tbody>
                                </table>
                            </div>
                        </div>

                        <div className="flex justify-between">
                            <Button variant="outline" onClick={handleBack}>
                                <ArrowLeft className="size-4 mr-2" />
                                Back
                            </Button>
                            <Button onClick={handleImport} className="bg-green-600 hover:bg-green-700">
                                Start Import
                            </Button>
                        </div>
                    </div>
                )}
            </DialogContent>
        </Dialog>
    );
}
