import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useTranslation } from '@/hooks/use-translation';
import { cn } from '@/lib/utils';
import axios, { AxiosError } from 'axios';
import { CheckCircle2, CircleSlash, Eye, TriangleAlert, UserRound } from 'lucide-react';
import { useEffect, useState } from 'react';
import { toast } from 'sonner';
import type { CinState, OwnerOption } from '../types';
import { OwnerFormFields, type OwnerFormShape } from './OwnerFormFields';

/**
 * The selected propriétaire's fiche: the same fields as the creation form
 * (OwnerFormFields), prefilled from the record and editable in place, so an
 * incomplete propriétaire — missing CIN number, missing ID photo — can be fixed
 * without leaving the dossier being created.
 *
 * The two CIN file inputs keep their upload role but gain a status line above
 * them: recorded and readable ("Voir"), recorded but the file is gone from the
 * disk, or nothing recorded at all.
 */
const CIN_STYLES: Record<CinState, { wrapper: string; text: string }> = {
    available: {
        wrapper: 'border-emerald-200 bg-emerald-50 dark:border-emerald-900 dark:bg-emerald-950/40',
        text: 'text-emerald-700 dark:text-emerald-400',
    },
    file_missing: {
        wrapper: 'border-red-200 bg-red-50 dark:border-red-900 dark:bg-red-950/40',
        text: 'text-red-700 dark:text-red-400',
    },
    none: {
        wrapper: 'border-amber-200 bg-amber-50 dark:border-amber-900 dark:bg-amber-950/40',
        text: 'text-amber-700 dark:text-amber-400',
    },
};

const CinField = ({
    label,
    state,
    inputId,
    onFile,
    onView,
    disabled,
}: {
    label: string;
    state: CinState;
    inputId: string;
    onFile: (file: File | null) => void;
    onView: () => void;
    disabled: boolean;
}) => {
    const { t } = useTranslation();
    const styles = CIN_STYLES[state];
    const Icon = state === 'available' ? CheckCircle2 : state === 'file_missing' ? TriangleAlert : CircleSlash;
    const message =
        state === 'available' ? t('crm', 'cin_on_file') : state === 'file_missing' ? t('crm', 'cin_file_missing') : t('crm', 'cin_missing');

    return (
        <div>
            <Label htmlFor={inputId}>{label}</Label>
            <div className={cn('mt-1 flex items-center justify-between gap-2 rounded-md border px-3 py-2', styles.wrapper)}>
                <span className={cn('flex items-center gap-1.5 text-xs font-medium', styles.text)}>
                    <Icon className="h-4 w-4 shrink-0" />
                    {message}
                </span>
                {state === 'available' && (
                    <Button type="button" variant="outline" size="sm" className="h-7 shrink-0 px-2" onClick={onView}>
                        <Eye className="mr-1 h-3.5 w-3.5" />
                        {t('crm', 'cin_view')}
                    </Button>
                )}
            </div>
            <Input
                type="file"
                id={inputId}
                className="mt-2"
                accept="image/*"
                disabled={disabled}
                onChange={(e) => onFile(e.target.files ? e.target.files[0] : null)}
            />
            <p className="text-muted-foreground mt-1 text-xs">{state === 'none' ? t('crm', 'cin_upload_hint') : t('crm', 'cin_replace_hint')}</p>
        </div>
    );
};

const toFormShape = (owner: OwnerOption): OwnerFormShape => ({
    name: owner.name ?? '',
    last_name: owner.last_name ?? '',
    civilite: owner.civilite ?? '',
    cin: owner.cin ?? '',
    pay_origine: owner.pay_origine ?? '',
    email: owner.email ?? '',
    phone: owner.phone ?? '',
    prefix_phone: owner.prefix_phone ?? '',
    password: '',
    photo_cin_recto: null,
    photo_cin_verso: null,
});

export const SelectedOwnerPanel = ({
    owner,
    phonesPrefix,
    onChangeOwner,
    onOwnerUpdated,
    embedded = false,
}: {
    owner: OwnerOption;
    phonesPrefix: string[];
    /** Omit where the propriétaire is fixed (EditFolderDialog): hides "Changer". */
    onChangeOwner?: () => void;
    onOwnerUpdated: (owner: OwnerOption) => void;
    /**
     * Drop the card chrome and the header. Set it when the surrounding UI already
     * frames and names this fiche (the accordion section of EditFolderDialog) —
     * otherwise the operator gets a box inside a box repeating the same name, and
     * the double padding squeezes the fields.
     */
    embedded?: boolean;
}) => {
    const { t } = useTranslation();
    const [data, setData] = useState<OwnerFormShape>(() => toFormShape(owner));
    const [errors, setErrors] = useState<Partial<Record<keyof OwnerFormShape, string>>>({});
    const [processing, setProcessing] = useState(false);

    // Reseed when the operator picks a different propriétaire.
    useEffect(() => {
        setData(toFormShape(owner));
        setErrors({});
    }, [owner]);

    const updateField = <K extends keyof OwnerFormShape>(key: K, value: OwnerFormShape[K]) => {
        setData((prev) => ({ ...prev, [key]: value }));
        if (errors[key]) {
            setErrors((prev) => {
                const next = { ...prev };
                delete next[key];
                return next;
            });
        }
    };

    // Opened in a new tab rather than an <img> preview: the browser's own viewer
    // handles both the large photos and the occasional PDF scan.
    const viewCin = (side: 'recto' | 'verso') => {
        window.open(route('crm.onboarding.owners.cin', { owner: owner.id, side }), '_blank', 'noopener,noreferrer');
    };

    const submit = async () => {
        if (processing) return;
        setProcessing(true);
        setErrors({});
        try {
            const formData = new FormData();
            formData.append('name', data.name);
            formData.append('last_name', data.last_name);
            formData.append('civilite', data.civilite);
            formData.append('cin', data.cin);
            formData.append('pay_origine', data.pay_origine);
            formData.append('email', data.email);
            formData.append('phone', data.phone);
            formData.append('prefix_phone', data.prefix_phone);
            if (data.password) formData.append('password', data.password);
            if (data.photo_cin_recto) formData.append('photo_cin_recto', data.photo_cin_recto);
            if (data.photo_cin_verso) formData.append('photo_cin_verso', data.photo_cin_verso);

            const response = await axios.post(route('crm.onboarding.owners.quick-update', { owner: owner.id }), formData, {
                headers: { 'Content-Type': 'multipart/form-data' },
            });

            toast.success(t('crm', 'owner_updated_success'));
            // The server moves every dossier that pointed at the old address; say so,
            // because that is a change the operator did not explicitly ask for.
            const movedFolders = Number(response.data.moved_folders ?? 0);
            if (movedFolders > 0) {
                toast.info(`${movedFolders} ${t('crm', 'owner_email_moved_folders')}`);
            }
            onOwnerUpdated(response.data.owner as OwnerOption);
        } catch (err) {
            const axiosError = err as AxiosError<{ errors?: Record<string, string[]>; message?: string }>;
            if (axiosError.response?.status === 422 && axiosError.response.data.errors) {
                const serverErrors: Partial<Record<keyof OwnerFormShape, string>> = {};
                Object.entries(axiosError.response.data.errors).forEach(([key, messages]) => {
                    serverErrors[key as keyof OwnerFormShape] = messages[0];
                    toast.error(messages[0]);
                });
                setErrors(serverErrors);
            } else {
                toast.error(axiosError.response?.data?.message ?? t('crm', 'owner_update_error'));
            }
        } finally {
            setProcessing(false);
        }
    };

    // Enter must save the fiche, never bubble up and send the wizard to step 2.
    const handleKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
        if (e.key !== 'Enter') return;
        const target = e.target as HTMLElement;
        if (target.tagName === 'TEXTAREA') return;
        e.preventDefault();
        e.stopPropagation();
        void submit();
    };

    return (
        <div className={cn(!embedded && 'bg-muted/30 rounded-lg border p-4')} onKeyDown={handleKeyDown}>
            {!embedded && (
                <div className="flex items-start justify-between gap-2">
                    <div>
                        <h4 className="text-secondary flex items-center gap-2 text-sm font-semibold">
                            <UserRound className="h-4 w-4" />
                            {owner.name} {owner.last_name ?? ''}
                        </h4>
                        <p className="text-muted-foreground mt-1 text-xs">{t('crm', 'selected_owner_description')}</p>
                    </div>
                    {onChangeOwner && (
                        <Button type="button" variant="outline" size="sm" onClick={onChangeOwner} disabled={processing}>
                            {t('crm', 'owner_change')}
                        </Button>
                    )}
                </div>
            )}

            <OwnerFormFields
                data={data}
                setData={updateField}
                errors={errors}
                phonesPrefix={phonesPrefix}
                nativeRequired={false}
                passwordOptional
                cinFields={
                    <>
                        <CinField
                            label={t('crm', 'photo_cin_recto')}
                            state={owner.cin_recto ?? 'none'}
                            inputId="selected_owner_cin_recto"
                            disabled={processing}
                            onFile={(file) => updateField('photo_cin_recto', file)}
                            onView={() => viewCin('recto')}
                        />
                        <CinField
                            label={t('crm', 'photo_cin_verso')}
                            state={owner.cin_verso ?? 'none'}
                            inputId="selected_owner_cin_verso"
                            disabled={processing}
                            onFile={(file) => updateField('photo_cin_verso', file)}
                            onView={() => viewCin('verso')}
                        />
                    </>
                }
            />

            <Button type="button" className="bg-secondary mt-4 w-full" onClick={() => void submit()} disabled={processing}>
                {processing ? t('crm', 'processing') : t('crm', 'owner_save_changes')}
            </Button>
        </div>
    );
};
