import React, { useCallback, useEffect, useState } from 'react';
import { AlertTriangle, CheckCircle2, ClipboardList, Loader2, Save, ShieldAlert } from 'lucide-react';
import toast from 'react-hot-toast';
import { getGenerationReadiness, postProjectFacts } from '../../api/client';

type MissingField = {
    field: string;
    label: string;
    category: string;
    hint?: string;
};

/** Spine report slice attached by backend apply_eligibility_to_completeness. */
type MspSlice = {
    status?: string;
    confidence?: number;
    source?: string;
    is_sme?: boolean;
    is_large?: boolean;
    message?: string;
};

type DeMinimisSlice = {
    used_eur?: number | null;
    limit_eur?: number;
    remaining_eur?: number | null;
    exhausted?: boolean;
    source?: string;
    configured?: boolean;
    message?: string;
};

export type EligibilityReport = {
    nip?: string;
    msp?: MspSlice;
    de_minimis?: DeMinimisSlice;
    blockers?: string[];
    ready_for_full_autopilot?: boolean;
    spine_enabled?: boolean;
    eligible_instrument_kinds?: string[];
};

export type Readiness = {
    status?: string;
    ready_to_generate?: boolean;
    full_autopilot_allowed?: boolean;
    missing_fields?: MissingField[];
    warnings?: string[];
    instrument_family?: string;
    dossier_level?: string;
    eligibility?: EligibilityReport;
    eligibility_spine_enforced?: boolean;
};

type Props = {
    projectId: string;
    onReadyChange?: (ready: boolean, readiness: Readiness | null) => void;
};

const MSP_LABELS: Record<string, string> = {
    mikro: 'Mikro',
    mala: 'Mała',
    srednia: 'Średnia',
    duza: 'Duża',
    unknown: 'Nieustalony',
};

/** Pure: format MŚP status for UI (fail-closed on empty/unknown). */
export function formatMspLabel(status?: string | null): string {
    const key = String(status || 'unknown').toLowerCase().trim();
    return MSP_LABELS[key] || MSP_LABELS.unknown;
}

/** Pure: format EUR amounts; null/undefined → "brak danych" (fail-closed). */
export function formatEur(value?: number | null): string {
    if (value === null || value === undefined || Number.isNaN(Number(value))) {
        return 'brak danych';
    }
    return `${Number(value).toLocaleString('pl-PL', { maximumFractionDigits: 0 })} EUR`;
}

/**
 * Pure: whether readiness payload warrants an Eligibility (MŚP / de minimis) section.
 * Show when:
 * - `readiness.eligibility` report is present (incl. blockers), or
 * - any `missing_fields` entry has `category === 'eligibility'`.
 */
export function shouldShowEligibilitySection(readiness: Readiness | null | undefined): boolean {
    if (!readiness) return false;
    if (readiness.eligibility && typeof readiness.eligibility === 'object') return true;
    const missing = readiness.missing_fields || [];
    return missing.some((m) => m.category === 'eligibility');
}

/**
 * Pure: spine is product-gated (enforced) for this readiness payload.
 * Explicit `false` on either flag → informational only.
 * Absent flags → treat as enforced (fail-closed).
 */
export function isEligibilitySpineEnforced(readiness: Readiness | null | undefined): boolean {
    if (!readiness) return true;
    const elig = readiness.eligibility;
    if (readiness.eligibility_spine_enforced === false) return false;
    if (elig && typeof elig === 'object' && elig.spine_enabled === false) return false;
    return true;
}

/**
 * Pure: eligibility is blocking Full Autopilot messaging (fail-closed).
 *
 * Rules:
 * - No readiness → blocked
 * - No eligibility report → blocked only if missing_fields category eligibility
 * - Explicit blockers → always blocked (hard signal)
 * - Spine not enforced (`eligibility_spine_enforced === false` / `spine_enabled === false`)
 *   → informational only (do not claim FA blocked by eligibility)
 * - `ready_for_full_autopilot === true` → not blocked
 * - `ready_for_full_autopilot === false` → blocked
 * - ready flag absent under enforced spine → local heuristics fail-closed
 *   (unknown/missing MŚP, large firm, exhausted or unknown de minimis)
 */
export function isEligibilityBlocking(readiness: Readiness | null | undefined): boolean {
    if (!readiness) return true;
    const elig = readiness.eligibility;
    if (!elig || typeof elig !== 'object') {
        return (readiness.missing_fields || []).some((m) => m.category === 'eligibility');
    }

    if (Array.isArray(elig.blockers) && elig.blockers.length > 0) return true;

    // Spine attached for transparency but not product-gated → no fail-closed FA claim
    if (!isEligibilitySpineEnforced(readiness)) {
        return false;
    }

    if (elig.ready_for_full_autopilot === true) return false;
    if (elig.ready_for_full_autopilot === false) return true;

    // ready flag absent: fail-closed local heuristics
    const mspStatus = String(elig.msp?.status || 'unknown').toLowerCase().trim();
    if (mspStatus === 'unknown' || Boolean(elig.msp?.is_large)) return true;
    if (Boolean(elig.de_minimis?.exhausted)) return true;
    // used_eur === 0 is a valid known total — only null/undefined is missing
    if (elig.de_minimis?.used_eur === null || elig.de_minimis?.used_eur === undefined) {
        return true;
    }
    return false;
}

/** Pure: short banner copy for the eligibility section (fail-closed tone). */
export function eligibilityBannerMessage(readiness: Readiness | null | undefined): {
    tone: 'blocked' | 'ok' | 'info';
    text: string;
} {
    if (isEligibilityBlocking(readiness)) {
        return {
            tone: 'blocked',
            text:
                'Full Autopilot zablokowany do czasu weryfikacji kwalifikowalności (fail-closed). ' +
                'Brak wiarygodnego statusu MŚP lub de minimis nie jest traktowany jako „OK”.',
        };
    }
    if (!isEligibilitySpineEnforced(readiness)) {
        return {
            tone: 'info',
            text:
                'Spine kwalifikowalności w trybie informacyjnym (nie egzekwowany) — nie bramkuje Full Autopilot. ' +
                'Status MŚP / de minimis poniżej tylko do wglądu.',
        };
    }
    return {
        tone: 'ok',
        text: 'Spine kwalifikowalności OK — MŚP i de minimis nie blokują Full Autopilot.',
    };
}

/**
 * Instrument-first HITL: show missing fields before Full Autopilot; save via project-facts.
 * When payload includes eligibility / blockers / missing category eligibility — show MŚP / de minimis.
 */
const GenerationReadinessPanel: React.FC<Props> = ({ projectId, onReadyChange }) => {
    const [loading, setLoading] = useState(true);
    const [saving, setSaving] = useState(false);
    const [readiness, setReadiness] = useState<Readiness | null>(null);
    const [schemaLabel, setSchemaLabel] = useState<string>('');
    const [values, setValues] = useState<Record<string, string>>({});

    const load = useCallback(async () => {
        setLoading(true);
        try {
            const data = await getGenerationReadiness(projectId);
            const r = (data?.readiness || {}) as Readiness;
            setReadiness(r);
            const schema = data?.instrument_schema || {};
            setSchemaLabel(
                [schema.label, schema.family, schema.budget_form].filter(Boolean).join(' · ') || '',
            );
            const init: Record<string, string> = {};
            for (const m of r.missing_fields || []) {
                init[m.field] = values[m.field] || '';
            }
            setValues((prev) => ({ ...init, ...prev }));
            onReadyChange?.(Boolean(r.full_autopilot_allowed), r);
        } catch {
            setReadiness(null);
            onReadyChange?.(false, null);
        } finally {
            setLoading(false);
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps -- reload on projectId only
    }, [projectId, onReadyChange]);

    useEffect(() => {
        load();
    }, [load]);

    const missing = readiness?.missing_fields || [];
    const eligibilityMissing = missing.filter((m) => m.category === 'eligibility');
    const otherMissing = missing.filter((m) => m.category !== 'eligibility');
    const allowed = Boolean(readiness?.full_autopilot_allowed);
    const status = readiness?.status || 'unknown';
    const elig = readiness?.eligibility;
    const showEligibility = shouldShowEligibilitySection(readiness);
    const eligibilityBlocked = isEligibilityBlocking(readiness);
    const eligibilityBanner = eligibilityBannerMessage(readiness);
    const blockers = Array.isArray(elig?.blockers) ? elig!.blockers! : [];

    const statusColor =
        allowed || status === 'structure_only'
            ? '#34d399'
            : status === 'blocked_dossier' || eligibilityBlocked
              ? '#f87171'
              : '#fbbf24';

    const eligibilityBorder =
        eligibilityBanner.tone === 'blocked'
            ? '#f8717166'
            : eligibilityBanner.tone === 'ok'
              ? '#34d39944'
              : '#fbbf2444';
    const eligibilityBg =
        eligibilityBanner.tone === 'blocked'
            ? 'rgba(248,113,113,0.08)'
            : eligibilityBanner.tone === 'ok'
              ? 'rgba(52,211,153,0.06)'
              : 'rgba(251,191,36,0.08)';
    const eligibilityIconColor =
        eligibilityBanner.tone === 'blocked'
            ? '#f87171'
            : eligibilityBanner.tone === 'ok'
              ? '#34d399'
              : '#fbbf24';
    const eligibilityTextColor =
        eligibilityBanner.tone === 'blocked'
            ? '#fecaca'
            : eligibilityBanner.tone === 'ok'
              ? '#a7f3d0'
              : '#fde68a';

    const handleSave = async () => {
        setSaving(true);
        try {
            const facts: Record<string, unknown> = {};
            const company: Record<string, unknown> = {};
            for (const m of missing) {
                const v = (values[m.field] || '').trim();
                if (!v) continue;
                if (m.category === 'company') {
                    if (m.field === 'company_name') company.name = v;
                    else if (m.field === 'pkd_codes') {
                        company.pkd_codes = v.split(/[,;]+/).map((s) => s.trim()).filter(Boolean);
                    } else if (m.field === 'employment_fte') {
                        company.employment_fte = Number(v) || v;
                    } else if (m.field === 'closed_financial_year') {
                        company.closed_financial_year = /^(1|true|tak|yes)$/i.test(v);
                    } else {
                        company[m.field] = v;
                    }
                } else if (m.category === 'eligibility') {
                    // Map spine HITL fields into company_data so rebuild sees them
                    if (m.field === 'msp_status') {
                        company.msp_status = v.toLowerCase().trim();
                    } else if (m.field === 'de_minimis_manual_eur') {
                        const n = Number(String(v).replace(/\s/g, '').replace(',', '.'));
                        company.de_minimis_manual_eur = Number.isFinite(n) ? n : v;
                    } else if (m.field === 'nip') {
                        company.nip = v;
                    } else if (m.field !== 'de_minimis_exhausted') {
                        company[m.field] = v;
                    }
                } else if (m.field === 'lump_sum_amount_pln') {
                    facts[m.field] = Number(String(v).replace(/\s/g, '').replace(',', '.')) || v;
                } else {
                    facts[m.field] = v;
                }
            }
            if (Object.keys(company).length) facts.company = company;
            if (!Object.keys(facts).length) {
                toast.error('Wpisz wartości w brakujących polach.');
                return;
            }
            const res = await postProjectFacts(projectId, facts);
            const r = (res?.readiness || {}) as Readiness;
            setReadiness(r);
            onReadyChange?.(Boolean(r.full_autopilot_allowed), r);
            if (r.full_autopilot_allowed) {
                toast.success('Dane uzupełnione — można uruchomić Full Autopilot.');
            } else {
                toast.success('Zapisano. Nadal brakuje niektórych pól.');
                await load();
            }
        } catch (err: unknown) {
            const detail = (err as { response?: { data?: { detail?: string } } })?.response?.data?.detail;
            toast.error(typeof detail === 'string' ? detail : 'Nie udało się zapisać faktów.');
        } finally {
            setSaving(false);
        }
    };

    if (loading) {
        return (
            <div className="glass-card" style={{ padding: '1rem 1.25rem', color: 'var(--text-muted)' }}>
                <Loader2 size={16} className="spin" style={{ display: 'inline', marginRight: 8 }} />
                Sprawdzam gotowość generacji…
            </div>
        );
    }

    if (!readiness) return null;

    const mspStatus = elig?.msp?.status || 'unknown';
    const mspOk = mspStatus !== 'unknown' && !elig?.msp?.is_large;
    const dm = elig?.de_minimis;
    const dmKnown = dm?.used_eur !== null && dm?.used_eur !== undefined;
    const dmOk = dmKnown && !dm?.exhausted;

    return (
        <div
            className="glass-card"
            style={{
                padding: '1.15rem 1.35rem',
                border: `1px solid ${statusColor}55`,
                background: `${statusColor}0d`,
            }}
        >
            <div style={{ display: 'flex', gap: '0.65rem', alignItems: 'flex-start', marginBottom: '0.75rem' }}>
                {allowed ? (
                    <CheckCircle2 size={22} color="#34d399" style={{ flexShrink: 0 }} />
                ) : (
                    <ClipboardList size={22} color={statusColor} style={{ flexShrink: 0 }} />
                )}
                <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 700, color: '#fff', fontSize: '1rem' }}>
                        Gotowość do generacji
                        <span style={{ marginLeft: 8, fontSize: '0.8rem', color: statusColor, fontWeight: 600 }}>
                            {status}
                        </span>
                    </div>
                    {schemaLabel && (
                        <div style={{ fontSize: '0.8rem', color: 'var(--text-muted)', marginTop: 2 }}>
                            Instrument: {schemaLabel}
                            {readiness.dossier_level ? ` · dossier: ${readiness.dossier_level}` : ''}
                        </div>
                    )}
                    {allowed ? (
                        <p style={{ margin: '0.4rem 0 0', color: '#a7f3d0', fontSize: '0.9rem' }}>
                            Dane wymagane przez instrument są kompletne — możesz uruchomić Full Autopilot.
                        </p>
                    ) : (
                        <p style={{ margin: '0.4rem 0 0', color: '#e5e7eb', fontSize: '0.9rem', lineHeight: 1.5 }}>
                            Uzupełnij brakujące pola (wymagane przez instrument), zanim wygenerujemy pełny wniosek.
                            Unikamy wypełniania „na ślepo” placeholderami.
                        </p>
                    )}
                </div>
            </div>

            {showEligibility && (
                <div
                    data-testid="eligibility-section"
                    style={{
                        marginBottom: '0.9rem',
                        padding: '0.85rem 1rem',
                        borderRadius: 10,
                        border: `1px solid ${eligibilityBorder}`,
                        background: eligibilityBg,
                    }}
                >
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 8 }}>
                        <ShieldAlert
                            size={18}
                            color={eligibilityIconColor}
                            style={{ flexShrink: 0 }}
                        />
                        <div style={{ fontWeight: 700, color: '#fff', fontSize: '0.92rem' }}>
                            Kwalifikowalność (MŚP / de minimis)
                        </div>
                    </div>

                    <p
                        data-testid={
                            eligibilityBanner.tone === 'blocked'
                                ? 'eligibility-fail-closed'
                                : eligibilityBanner.tone === 'info'
                                  ? 'eligibility-info'
                                  : 'eligibility-ok'
                        }
                        style={{
                            margin: '0 0 0.65rem',
                            color: eligibilityTextColor,
                            fontSize: '0.85rem',
                            lineHeight: 1.45,
                        }}
                    >
                        {eligibilityBanner.text}
                    </p>

                    <div
                        style={{
                            display: 'grid',
                            gridTemplateColumns: '1fr 1fr',
                            gap: '0.65rem',
                            fontSize: '0.82rem',
                        }}
                    >
                        <div
                            style={{
                                padding: '0.55rem 0.7rem',
                                borderRadius: 8,
                                background: 'rgba(0,0,0,0.25)',
                                border: `1px solid ${mspOk ? '#34d39933' : '#f8717144'}`,
                            }}
                        >
                            <div style={{ color: 'var(--text-muted)', marginBottom: 2 }}>Status MŚP</div>
                            <div style={{ fontWeight: 700, color: mspOk ? '#a7f3d0' : '#fca5a5' }}>
                                {elig ? formatMspLabel(mspStatus) : 'brak raportu'}
                                {elig?.msp?.is_large ? ' · duża firma' : ''}
                            </div>
                            {elig?.msp?.source && (
                                <div style={{ color: 'var(--text-muted)', fontSize: '0.72rem', marginTop: 2 }}>
                                    źródło: {elig.msp.source}
                                    {typeof elig.msp.confidence === 'number'
                                        ? ` · conf. ${(elig.msp.confidence * 100).toFixed(0)}%`
                                        : ''}
                                </div>
                            )}
                            {elig?.msp?.message ? (
                                <div style={{ color: '#e5e7eb', fontSize: '0.72rem', marginTop: 4 }}>
                                    {elig.msp.message}
                                </div>
                            ) : null}
                        </div>

                        <div
                            style={{
                                padding: '0.55rem 0.7rem',
                                borderRadius: 8,
                                background: 'rgba(0,0,0,0.25)',
                                border: `1px solid ${dmOk ? '#34d39933' : '#f8717144'}`,
                            }}
                        >
                            <div style={{ color: 'var(--text-muted)', marginBottom: 2 }}>De minimis</div>
                            <div style={{ fontWeight: 700, color: dmOk ? '#a7f3d0' : '#fca5a5' }}>
                                {dm
                                    ? `${formatEur(dm.used_eur)} / ${formatEur(dm.limit_eur ?? 300_000)}`
                                    : 'brak raportu'}
                            </div>
                            <div style={{ color: 'var(--text-muted)', fontSize: '0.72rem', marginTop: 2 }}>
                                pozostało:{' '}
                                <span style={{ color: dm?.exhausted ? '#fca5a5' : undefined }}>
                                    {dm ? formatEur(dm.remaining_eur) : 'brak danych'}
                                </span>
                                {dm?.exhausted ? ' · wyczerpany' : ''}
                            </div>
                            {dm?.source && (
                                <div style={{ color: 'var(--text-muted)', fontSize: '0.72rem', marginTop: 2 }}>
                                    źródło: {dm.source}
                                </div>
                            )}
                            {dm?.message ? (
                                <div style={{ color: '#e5e7eb', fontSize: '0.72rem', marginTop: 4 }}>
                                    {dm.message}
                                </div>
                            ) : null}
                        </div>
                    </div>

                    {blockers.length > 0 && (
                        <ul
                            data-testid="eligibility-blockers"
                            style={{
                                margin: '0.65rem 0 0',
                                paddingLeft: '1.15rem',
                                color: '#fecaca',
                                fontSize: '0.82rem',
                                lineHeight: 1.45,
                            }}
                        >
                            {blockers.map((b) => (
                                <li key={b}>{b}</li>
                            ))}
                        </ul>
                    )}

                    {!elig && eligibilityMissing.length > 0 && (
                        <p style={{ margin: '0.65rem 0 0', color: '#fde68a', fontSize: '0.8rem' }}>
                            Brak pełnego raportu spine — uzupełnij pola kwalifikowalności poniżej (fail-closed).
                        </p>
                    )}
                </div>
            )}

            {(readiness.warnings || []).length > 0 && (
                <ul style={{ margin: '0 0 0.75rem', paddingLeft: '1.2rem', color: '#fde68a', fontSize: '0.85rem' }}>
                    {readiness.warnings!.map((w) => (
                        <li key={w}>{w}</li>
                    ))}
                </ul>
            )}

            {missing.length > 0 && (
                <>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: '0.75rem' }}>
                        {/* Eligibility fields first for visibility */}
                        {[...eligibilityMissing, ...otherMissing].map((m) => (
                            <label key={m.field} style={{ display: 'block' }}>
                                <span
                                    style={{
                                        display: 'block',
                                        fontSize: '0.8rem',
                                        color: m.category === 'eligibility' ? '#fca5a5' : '#fbbf24',
                                        marginBottom: 4,
                                    }}
                                >
                                    <AlertTriangle size={12} style={{ display: 'inline', marginRight: 4 }} />
                                    {m.label}
                                    <span style={{ color: 'var(--text-muted)', fontWeight: 400 }}>
                                        {' '}
                                        ({m.category})
                                    </span>
                                </span>
                                {m.hint && (
                                    <span
                                        style={{
                                            display: 'block',
                                            fontSize: '0.75rem',
                                            color: 'var(--text-muted)',
                                            marginBottom: 4,
                                        }}
                                    >
                                        {m.hint}
                                    </span>
                                )}
                                {m.field === 'de_minimis_exhausted' ? (
                                    <div
                                        style={{
                                            padding: '0.55rem 0.75rem',
                                            borderRadius: 8,
                                            border: '1px solid rgba(248,113,113,0.35)',
                                            background: 'rgba(248,113,113,0.08)',
                                            color: '#fecaca',
                                            fontSize: '0.85rem',
                                        }}
                                    >
                                        Limit wyczerpany — nie da się „uzupełnić” w formularzu. Wybierz instrument bez de
                                        minimis lub zmień strategię.
                                    </div>
                                ) : (
                                    <input
                                        value={values[m.field] || ''}
                                        onChange={(e) => setValues((v) => ({ ...v, [m.field]: e.target.value }))}
                                        placeholder={
                                            m.field === 'msp_status'
                                                ? 'mikro | mala | srednia | duza'
                                                : m.field === 'de_minimis_manual_eur'
                                                  ? 'np. 45000'
                                                  : m.field
                                        }
                                        style={{
                                            width: '100%',
                                            padding: '0.55rem 0.75rem',
                                            borderRadius: 8,
                                            border: '1px solid rgba(255,255,255,0.12)',
                                            background: 'rgba(0,0,0,0.35)',
                                            color: '#fff',
                                            fontSize: '0.9rem',
                                        }}
                                    />
                                )}
                            </label>
                        ))}
                    </div>
                    <button
                        type="button"
                        onClick={handleSave}
                        disabled={saving}
                        style={{
                            marginTop: '1rem',
                            display: 'inline-flex',
                            alignItems: 'center',
                            gap: 8,
                            padding: '0.55rem 1rem',
                            borderRadius: 8,
                            border: 'none',
                            background: '#2563eb',
                            color: '#fff',
                            fontWeight: 700,
                            fontSize: '0.85rem',
                            cursor: saving ? 'wait' : 'pointer',
                        }}
                    >
                        {saving ? <Loader2 size={16} className="spin" /> : <Save size={16} />}
                        Zapisz i sprawdź ponownie
                    </button>
                </>
            )}
        </div>
    );
};

export default GenerationReadinessPanel;
