import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Select, SelectContent, SelectGroup, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useTranslation } from '@/hooks/use-translation';
import { type FormDataConvertible } from '@inertiajs/core';
import { router } from '@inertiajs/react';
import { AlertTriangle, Loader2, Plus, Trash2 } from 'lucide-react';
import { useMemo, useState } from 'react';
import { toast } from 'sonner';
import { FEE_COLLECT_TIMES } from './constants';

const CHUNK_SIZE = 5;

type FieldKey = 'price' | 'cancellation_policies' | 'additional_fees' | 'check_in_out' | 'preparation_time';

type Option = { id: number | string; name: string };

type CheckInOut = { check_in_from: string; check_in_to: string; check_out_until: string; place: string };
type Policy = { valid_from: string; valid_to: string; charge: string };
type Fee = { typeId: string; name: string; discriminatorId: string; amount: string; optional: boolean };
type Price = { start_date: string; end_date: string; daily_price: string; name: string };

type BulkFailure = { uid: string; name: string | null; reason: string };
type BulkResult = { succeeded?: string[]; failed?: BulkFailure[]; fatal?: string };

interface BulkEditDialogProps {
    open: boolean;
    onOpenChange: (open: boolean) => void;
    selectedUids: string[];
    feeTypes: Option[];
    feeDiscriminators: Option[];
    onDone: () => void;
}

const PLACES = ['apartment', 'property', 'office', 'airport', 'other'] as const;

function chunkArray<T>(arr: T[], size: number): T[][] {
    const out: T[][] = [];
    for (let i = 0; i < arr.length; i += size) {
        out.push(arr.slice(i, i + size));
    }
    return out;
}

export default function BulkEditDialog({ open, onOpenChange, selectedUids, feeTypes, feeDiscriminators, onDone }: BulkEditDialogProps) {
    const { t } = useTranslation();

    const [field, setField] = useState<FieldKey>('check_in_out');

    // Per-field editor state
    const [checkInOut, setCheckInOut] = useState<CheckInOut>({ check_in_from: '', check_in_to: '', check_out_until: '', place: 'apartment' });
    const [prepValue, setPrepValue] = useState('');
    const [prepUnit, setPrepUnit] = useState<'hours' | 'days'>('hours');
    const [policies, setPolicies] = useState<Policy[]>([{ valid_from: '', valid_to: '', charge: '' }]);
    const [fees, setFees] = useState<Fee[]>([{ typeId: '', name: '', discriminatorId: '', amount: '', optional: false }]);
    const [price, setPrice] = useState<Price>({ start_date: '', end_date: '', daily_price: '', name: '' });

    // Progress state
    const [running, setRunning] = useState(false);
    const [finished, setFinished] = useState(false);
    const [processed, setProcessed] = useState(0);
    const [total, setTotal] = useState(0);
    const [succeeded, setSucceeded] = useState<string[]>([]);
    const [failed, setFailed] = useState<BulkFailure[]>([]);

    const fieldLabel = (key: FieldKey) => t('properties.bulk-edit', `field_${key}`);

    const progressPct = total > 0 ? Math.round((processed / total) * 100) : 0;

    const buildValue = (): Record<string, unknown> | null => {
        switch (field) {
            case 'check_in_out':
                if (!checkInOut.check_in_from || !checkInOut.check_in_to || !checkInOut.check_out_until) return null;
                return { ...checkInOut };
            case 'preparation_time': {
                const n = parseInt(prepValue, 10);
                if (Number.isNaN(n) || n < 0) return null;
                return { hours: prepUnit === 'days' ? n * 24 : n };
            }
            case 'cancellation_policies': {
                const clean = policies
                    .filter((p) => p.valid_from !== '' && p.valid_to !== '' && p.charge !== '')
                    .map((p) => ({ valid_from: parseInt(p.valid_from, 10), valid_to: parseInt(p.valid_to, 10), charge: parseFloat(p.charge) }));
                if (clean.length === 0) return null;
                return { policies: clean };
            }
            case 'additional_fees': {
                const clean = fees
                    .filter((f) => f.typeId !== '' && f.discriminatorId !== '' && f.name !== '' && f.amount !== '')
                    .map((f) => ({
                        name: f.name,
                        discriminatorId: parseInt(f.discriminatorId, 10),
                        typeId: parseInt(f.typeId, 10),
                        collectTime: FEE_COLLECT_TIMES.AT_BOOKING,
                        amount: parseFloat(f.amount),
                        optional: f.optional,
                    }));
                if (clean.length === 0) return null;
                return { fees: clean };
            }
            case 'price':
                if (!price.start_date || !price.end_date || price.daily_price === '') return null;
                return { start_date: price.start_date, end_date: price.end_date, daily_price: parseFloat(price.daily_price), name: price.name };
            default:
                return null;
        }
    };

    const value = useMemo(buildValue, [field, checkInOut, prepValue, prepUnit, policies, fees, price]);
    const canApply = value !== null && selectedUids.length > 0 && !running;

    const resetProgress = () => {
        setRunning(false);
        setFinished(false);
        setProcessed(0);
        setTotal(0);
        setSucceeded([]);
        setFailed([]);
    };

    const handleApply = () => {
        const payloadValue = buildValue();
        if (!payloadValue) return;

        const chunks = chunkArray(selectedUids, CHUNK_SIZE);
        setRunning(true);
        setFinished(false);
        setProcessed(0);
        setTotal(selectedUids.length);
        setSucceeded([]);
        setFailed([]);

        let okAcc: string[] = [];
        let failAcc: BulkFailure[] = [];
        let done = 0;

        const postChunk = (index: number) => {
            if (index >= chunks.length) {
                setRunning(false);
                setFinished(true);
                if (failAcc.length === 0) {
                    toast.success(`${okAcc.length} logement(s) mis à jour.`);
                } else {
                    toast.warning(`${okAcc.length} mis à jour, ${failAcc.length} en échec.`);
                }
                router.reload({ only: ['logements'] });
                return;
            }

            const currentChunk = chunks[index];

            router.post(
                route('logements.bulkUpdate'),
                { property_uids: currentChunk, field, value: payloadValue as FormDataConvertible },
                {
                    preserveState: true,
                    preserveScroll: true,
                    only: ['flash'],
                    onSuccess: (page) => {
                        const result = (page.props as { flash?: { bulk_result?: BulkResult } }).flash?.bulk_result;
                        if (result) {
                            okAcc = [...okAcc, ...(result.succeeded ?? [])];
                            failAcc = [...failAcc, ...(result.failed ?? [])];
                            if (result.fatal) {
                                failAcc = [...failAcc, ...currentChunk.map((uid) => ({ uid, name: null, reason: result.fatal as string }))];
                            }
                        }
                        done += currentChunk.length;
                        setProcessed(done);
                        setSucceeded(okAcc);
                        setFailed(failAcc);
                        postChunk(index + 1);
                    },
                    onError: () => {
                        failAcc = [...failAcc, ...currentChunk.map((uid) => ({ uid, name: null, reason: 'Erreur de validation.' }))];
                        done += currentChunk.length;
                        setProcessed(done);
                        setFailed(failAcc);
                        postChunk(index + 1);
                    },
                },
            );
        };

        postChunk(0);
    };

    const handleClose = (next: boolean) => {
        if (running) return; // don't allow closing mid-run
        if (!next && finished) {
            onDone();
        }
        resetProgress();
        onOpenChange(next);
    };

    // ---- Field editors ----

    const renderCheckInOut = () => (
        <div className="grid grid-cols-2 gap-3">
            <div>
                <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'check_in_from')}</Label>
                <Input type="time" value={checkInOut.check_in_from} onChange={(e) => setCheckInOut({ ...checkInOut, check_in_from: e.target.value })} />
            </div>
            <div>
                <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'check_in_to')}</Label>
                <Input type="time" value={checkInOut.check_in_to} onChange={(e) => setCheckInOut({ ...checkInOut, check_in_to: e.target.value })} />
            </div>
            <div>
                <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'check_out_until')}</Label>
                <Input type="time" value={checkInOut.check_out_until} onChange={(e) => setCheckInOut({ ...checkInOut, check_out_until: e.target.value })} />
            </div>
            <div>
                <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'place')}</Label>
                <Select value={checkInOut.place} onValueChange={(v) => setCheckInOut({ ...checkInOut, place: v })}>
                    <SelectTrigger>
                        <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                        <SelectGroup>
                            {PLACES.map((p) => (
                                <SelectItem key={p} value={p}>
                                    {t('properties.bulk-edit', `place_${p}`)}
                                </SelectItem>
                            ))}
                        </SelectGroup>
                    </SelectContent>
                </Select>
            </div>
        </div>
    );

    const renderPreparation = () => (
        <div className="flex flex-wrap items-end gap-2">
            <div className="flex-1">
                <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'prep_label')}</Label>
                <Input type="number" min={0} value={prepValue} onChange={(e) => setPrepValue(e.target.value)} />
            </div>
            <Select value={prepUnit} onValueChange={(v) => setPrepUnit(v as 'hours' | 'days')}>
                <SelectTrigger className="w-28">
                    <SelectValue />
                </SelectTrigger>
                <SelectContent>
                    <SelectGroup>
                        <SelectItem value="hours">{t('properties.bulk-edit', 'unit_hours')}</SelectItem>
                        <SelectItem value="days">{t('properties.bulk-edit', 'unit_days')}</SelectItem>
                    </SelectGroup>
                </SelectContent>
            </Select>
            <span className="text-muted-foreground pb-2 text-sm">{t('properties.bulk-edit', 'prep_before_arrival')}</span>
        </div>
    );

    const renderCancellation = () => (
        <div className="flex flex-col gap-3">
            {policies.map((policy, index) => (
                <div key={index} className="flex flex-wrap items-end gap-2 rounded-lg border p-3">
                    <div className="w-28">
                        <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'valid_from')}</Label>
                        <Input
                            type="number"
                            min={0}
                            value={policy.valid_from}
                            onChange={(e) => setPolicies(policies.map((p, i) => (i === index ? { ...p, valid_from: e.target.value } : p)))}
                        />
                    </div>
                    <div className="w-28">
                        <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'valid_to')}</Label>
                        <Input
                            type="number"
                            min={0}
                            value={policy.valid_to}
                            onChange={(e) => setPolicies(policies.map((p, i) => (i === index ? { ...p, valid_to: e.target.value } : p)))}
                        />
                    </div>
                    <div className="w-28">
                        <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'charge')}</Label>
                        <Input
                            type="number"
                            min={0}
                            max={100}
                            value={policy.charge}
                            onChange={(e) => setPolicies(policies.map((p, i) => (i === index ? { ...p, charge: e.target.value } : p)))}
                        />
                    </div>
                    {policies.length > 1 && (
                        <Button type="button" variant="ghost" size="icon" onClick={() => setPolicies(policies.filter((_, i) => i !== index))}>
                            <Trash2 className="h-4 w-4 text-red-500" />
                        </Button>
                    )}
                </div>
            ))}
            <Button type="button" variant="outline" size="sm" className="self-start" onClick={() => setPolicies([...policies, { valid_from: '', valid_to: '', charge: '' }])}>
                <Plus className="mr-1 h-4 w-4" /> {t('properties.bulk-edit', 'add_policy')}
            </Button>
        </div>
    );

    const renderFees = () => (
        <div className="flex flex-col gap-3">
            {fees.map((fee, index) => (
                <div key={index} className="flex flex-col gap-2 rounded-lg border p-3">
                    <div className="grid grid-cols-2 gap-2">
                        <div>
                            <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'fee_type')}</Label>
                            <Select value={fee.typeId} onValueChange={(v) => setFees(fees.map((f, i) => (i === index ? { ...f, typeId: v } : f)))}>
                                <SelectTrigger>
                                    <SelectValue placeholder={t('properties.bulk-edit', 'select_placeholder')} />
                                </SelectTrigger>
                                <SelectContent>
                                    <SelectGroup>
                                        {feeTypes.map((item) => (
                                            <SelectItem key={item.id} value={String(item.id)}>
                                                {item.name}
                                            </SelectItem>
                                        ))}
                                    </SelectGroup>
                                </SelectContent>
                            </Select>
                        </div>
                        <div>
                            <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'fee_discriminator')}</Label>
                            <Select value={fee.discriminatorId} onValueChange={(v) => setFees(fees.map((f, i) => (i === index ? { ...f, discriminatorId: v } : f)))}>
                                <SelectTrigger>
                                    <SelectValue placeholder={t('properties.bulk-edit', 'select_placeholder')} />
                                </SelectTrigger>
                                <SelectContent>
                                    <SelectGroup>
                                        {feeDiscriminators.map((item) => (
                                            <SelectItem key={item.id} value={String(item.id)}>
                                                {item.name}
                                            </SelectItem>
                                        ))}
                                    </SelectGroup>
                                </SelectContent>
                            </Select>
                        </div>
                        <div>
                            <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'fee_name')}</Label>
                            <Input value={fee.name} onChange={(e) => setFees(fees.map((f, i) => (i === index ? { ...f, name: e.target.value } : f)))} />
                        </div>
                        <div>
                            <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'fee_amount')}</Label>
                            <Input type="number" min={0} value={fee.amount} onChange={(e) => setFees(fees.map((f, i) => (i === index ? { ...f, amount: e.target.value } : f)))} />
                        </div>
                    </div>
                    <div className="flex items-center justify-between">
                        <label className="flex items-center gap-2 text-sm">
                            <Checkbox checked={fee.optional} onCheckedChange={(v) => setFees(fees.map((f, i) => (i === index ? { ...f, optional: v === true } : f)))} />
                            {t('properties.bulk-edit', 'fee_optional')}
                        </label>
                        {fees.length > 1 && (
                            <Button type="button" variant="ghost" size="icon" onClick={() => setFees(fees.filter((_, i) => i !== index))}>
                                <Trash2 className="h-4 w-4 text-red-500" />
                            </Button>
                        )}
                    </div>
                </div>
            ))}
            <Button
                type="button"
                variant="outline"
                size="sm"
                className="self-start"
                onClick={() => setFees([...fees, { typeId: '', name: '', discriminatorId: '', amount: '', optional: false }])}
            >
                <Plus className="mr-1 h-4 w-4" /> {t('properties.bulk-edit', 'add_fee')}
            </Button>
        </div>
    );

    const renderPrice = () => (
        <div className="flex flex-col gap-3">
            <div className="flex items-start gap-2 rounded-lg border border-amber-300 bg-amber-50 p-3 text-sm text-amber-800 dark:bg-amber-950/30 dark:text-amber-300">
                <AlertTriangle className="mt-0.5 h-4 w-4 shrink-0" />
                <span>{t('properties.bulk-edit', 'price_overwrite_warning')}</span>
            </div>
            <div className="grid grid-cols-2 gap-3">
                <div>
                    <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'price_start')}</Label>
                    <Input type="date" value={price.start_date} onChange={(e) => setPrice({ ...price, start_date: e.target.value })} />
                </div>
                <div>
                    <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'price_end')}</Label>
                    <Input type="date" value={price.end_date} onChange={(e) => setPrice({ ...price, end_date: e.target.value })} />
                </div>
            </div>
            <div className="grid grid-cols-2 gap-3">
                <div>
                    <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'daily_price')}</Label>
                    <Input type="number" min={0} value={price.daily_price} onChange={(e) => setPrice({ ...price, daily_price: e.target.value })} />
                </div>
                <div>
                    <Label className="mb-1 block text-xs">{t('properties.bulk-edit', 'season_name')}</Label>
                    <Input
                        value={price.name}
                        onChange={(e) => setPrice({ ...price, name: e.target.value })}
                        placeholder={t('properties.bulk-edit', 'season_name_placeholder')}
                    />
                </div>
            </div>
        </div>
    );

    const renderEditor = () => {
        switch (field) {
            case 'check_in_out':
                return renderCheckInOut();
            case 'preparation_time':
                return renderPreparation();
            case 'cancellation_policies':
                return renderCancellation();
            case 'additional_fees':
                return renderFees();
            case 'price':
                return renderPrice();
            default:
                return null;
        }
    };

    return (
        <Dialog open={open} onOpenChange={handleClose}>
            <DialogContent className="max-h-[90vh] overflow-y-auto sm:max-w-2xl">
                <DialogHeader>
                    <DialogTitle>{t('properties.bulk-edit', 'dialog_title')}</DialogTitle>
                    <DialogDescription>{t('properties.bulk-edit', 'dialog_description')}</DialogDescription>
                </DialogHeader>

                {running || finished ? (
                    <div className="flex flex-col gap-4 py-2">
                        <div className="flex items-center gap-2 text-sm">
                            {running && <Loader2 className="h-4 w-4 animate-spin" />}
                            <span>
                                {processed}/{total} — {succeeded.length} OK
                                {failed.length > 0 ? `, ${failed.length} ⚠` : ''}
                            </span>
                        </div>
                        <div className="bg-muted h-2 w-full overflow-hidden rounded-full">
                            <div className="bg-secondary h-full transition-all duration-300" style={{ width: `${progressPct}%` }} />
                        </div>
                        {failed.length > 0 && (
                            <div className="flex flex-col gap-1">
                                <p className="text-sm font-semibold">{t('properties.bulk-edit', 'failures_title')}</p>
                                <ul className="max-h-40 overflow-y-auto text-xs text-red-600">
                                    {failed.map((f, i) => (
                                        <li key={`${f.uid}-${i}`}>
                                            {f.name ?? f.uid} — {f.reason}
                                        </li>
                                    ))}
                                </ul>
                            </div>
                        )}
                    </div>
                ) : (
                    <div className="flex flex-col gap-4">
                        <div>
                            <Label className="mb-1 block text-sm font-medium">{t('properties.bulk-edit', 'choose_field')}</Label>
                            <Select value={field} onValueChange={(v) => setField(v as FieldKey)}>
                                <SelectTrigger>
                                    <SelectValue />
                                </SelectTrigger>
                                <SelectContent>
                                    <SelectGroup>
                                        <SelectItem value="check_in_out">{fieldLabel('check_in_out')}</SelectItem>
                                        <SelectItem value="preparation_time">{fieldLabel('preparation_time')}</SelectItem>
                                        <SelectItem value="cancellation_policies">{fieldLabel('cancellation_policies')}</SelectItem>
                                        <SelectItem value="additional_fees">{fieldLabel('additional_fees')}</SelectItem>
                                        <SelectItem value="price">{fieldLabel('price')}</SelectItem>
                                    </SelectGroup>
                                </SelectContent>
                            </Select>
                        </div>

                        {renderEditor()}

                        <p className="text-muted-foreground text-xs">{t('properties.bulk-edit', 'replace_warning')}</p>
                    </div>
                )}

                <DialogFooter>
                    {finished ? (
                        <Button onClick={() => handleClose(false)}>{t('properties.bulk-edit', 'close')}</Button>
                    ) : (
                        <>
                            <Button variant="outline" onClick={() => handleClose(false)} disabled={running}>
                                {t('properties.bulk-edit', 'cancel')}
                            </Button>
                            <Button onClick={handleApply} disabled={!canApply}>
                                {running ? (
                                    <>
                                        <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                                        {t('properties.bulk-edit', 'applying')}
                                    </>
                                ) : (
                                    `${t('properties.bulk-edit', 'apply')} (${selectedUids.length})`
                                )}
                            </Button>
                        </>
                    )}
                </DialogFooter>
            </DialogContent>
        </Dialog>
    );
}
