import { Link } from '@inertiajs/react';
import {
    ChevronDown,
    ChevronRight,
    Landmark,
    ListTree,
    TrendingDown,
    TrendingUp,
} from 'lucide-react';
import { useMemo, useState, type ReactNode } from 'react';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import {
    MonthlyGainsChart,
    type MonthChartPoint,
} from '@/pages/investments/components/monthly-gains-chart';
import type {
    InvestmentMonthPerf,
    UserPortfolioInvestment,
} from '@/pages/investments/types-user-portfolio';
import { formatCurrency } from '@/pages/investments/utils';
import { cn } from '@/lib/utils';

export function MyInvestmentsTable({
    investments,
}: {
    investments: UserPortfolioInvestment[];
}) {
    const [expandedRows, setExpandedRows] = useState<Record<number, boolean>>({});

    function toggle(id: number) {
        setExpandedRows((previous) => ({
            ...previous,
            [id]: !previous[id],
        }));
    }

    return (
        <div className="space-y-0 overflow-x-auto rounded-lg border">
            <table className="w-full min-w-[760px] text-left text-sm">
                <thead>
                    <tr className="border-b bg-muted/40 text-muted-foreground">
                        <th className="w-12 px-3 py-3 font-medium" />
                        <th className="px-3 py-3 font-medium">Estado</th>
                        <th className="px-3 py-3 font-medium">Principal</th>
                        <th className="hidden px-3 py-3 font-medium sm:table-cell">
                            Capital vigente
                        </th>
                        <th className="px-3 py-3 font-medium">Plazo</th>
                        <th className="min-w-[6rem] px-3 py-3 font-medium">
                            Plan % mensual
                        </th>
                        <th className="hidden px-3 py-3 font-medium md:table-cell">
                            Ganancia día (proy.)
                        </th>
                        <th className="hidden px-3 py-3 font-medium lg:table-cell">
                            Total al vencimiento (proy.)
                        </th>
                        <th className="hidden px-3 py-3 font-medium sm:table-cell">
                            Confirmación
                        </th>
                    </tr>
                </thead>
                <tbody className="divide-y">
                    {investments.flatMap((inv) => [
                        <tr className="bg-card align-middle" key={`${inv.id}-main`}>
                            <td className="px-1 py-2">
                                <Button
                                    aria-expanded={Boolean(expandedRows[inv.id])}
                                    className="size-8"
                                    onClick={() => toggle(inv.id)}
                                    size="icon"
                                    type="button"
                                    variant="ghost"
                                >
                                    {expandedRows[inv.id] ? (
                                        <ChevronDown className="size-4" />
                                    ) : (
                                        <ChevronRight className="size-4" />
                                    )}
                                </Button>
                            </td>
                            <td className="px-3 py-2">
                                <Badge
                                    variant={
                                        inv.status === 'pending'
                                            ? 'outline'
                                            : inv.status === 'completed'
                                              ? 'outline'
                                              : 'secondary'
                                    }
                                >
                                    {inv.status === 'pending'
                                        ? 'Pendiente'
                                        : inv.status === 'completed'
                                          ? 'Finalizada'
                                          : 'Activa'}
                                </Badge>
                            </td>
                            <td className="px-3 py-2 font-medium tabular-nums">
                                {formatCurrency(Number(inv.amount))}
                            </td>
                            <td className="hidden px-3 py-2 tabular-nums sm:table-cell">
                                {inv.status === 'pending' ? (
                                    <span className="text-muted-foreground">—</span>
                                ) : (
                                    <span className="font-semibold text-primary">
                                        {formatCurrency(
                                            Number(inv.current_capital_usd),
                                        )}
                                    </span>
                                )}
                            </td>
                            <td className="px-3 py-2 text-muted-foreground">
                                {inv.duration_months} meses
                            </td>
                            <td className="px-3 py-2 font-medium tabular-nums text-primary">
                                {Number(inv.monthly_return_snapshot).toLocaleString(
                                    'es-US',
                                    {
                                        minimumFractionDigits: 0,
                                        maximumFractionDigits: 4,
                                    },
                                )}
                                %
                            </td>
                            <td className="hidden px-3 py-2 tabular-nums md:table-cell">
                                {formatCurrency(Number(inv.projected_daily_gain))}
                            </td>
                            <td className="hidden px-3 py-2 font-medium tabular-nums lg:table-cell">
                                {formatCurrency(Number(inv.projected_ending_balance))}
                            </td>
                            <td className="hidden px-3 py-2 text-muted-foreground sm:table-cell">
                                {formatIsoDate(inv.confirmed_at)}
                            </td>
                        </tr>,
                        <tr
                            className={cn(
                                'bg-muted/20',
                                expandedRows[inv.id] ? '' : 'hidden',
                            )}
                            key={`${inv.id}-detail`}
                        >
                            <td className="p-4" colSpan={9}>
                                <InvestmentRowDetail investment={inv} />
                            </td>
                        </tr>,
                    ])}
                </tbody>
            </table>
        </div>
    );
}

/** Varios meses pactados como puntos; fracción `acreditados/plazo`. */
function MonthlyAccrualsProgress({
    monthsCredited,
    durationMonths,
    pending,
}: {
    monthsCredited: number;
    durationMonths: number;
    pending: boolean;
}) {
    const total = Math.max(1, durationMonths);
    const credited = pending ? 0 : Math.max(0, Math.min(total, monthsCredited));
    const showDots = total > 1 && total <= 18;
    const nextSlot = credited < total ? credited + 1 : null;

    return (
        <div className="flex flex-wrap items-center gap-x-2 gap-y-1">
            {showDots ? (
                <div
                    aria-hidden
                    className="flex shrink-0 flex-wrap gap-0.5"
                    title="Meses del plan"
                >
                    {Array.from({ length: total }, (_, idx) => {
                        const ordinal = idx + 1;

                        return (
                            <span
                                className={cn(
                                    'size-1.5 shrink-0 rounded-full transition-colors',
                                    ordinal <= credited
                                        ? 'bg-emerald-600 dark:bg-emerald-400'
                                        : nextSlot !== null && ordinal === nextSlot
                                          ? 'ring-foreground/70 box-border bg-primary shadow-sm ring-2 ring-offset-1 ring-offset-background'
                                          : 'bg-muted-foreground/35',
                                )}
                                key={ordinal}
                            />
                        );
                    })}
                </div>
            ) : null}
            <span className="text-base font-semibold tabular-nums leading-snug">
                {credited}/{total}
            </span>
        </div>
    );
}

function DetailStatMini({
    title,
    value,
}: {
    title: string;
    value: ReactNode;
}) {
    return (
        <div className="rounded-lg border bg-background px-3 py-2">
            <p className="text-xs leading-tight text-muted-foreground">{title}</p>
            <div className="mt-0.5 text-base font-semibold tabular-nums leading-snug">{value}</div>
        </div>
    );
}

function compareAccruedVsContract(
    accredited: number,
    contract: number,
): 'below' | 'above' | 'equal' {
    const tol = 0.0005;

    if (accredited < contract - tol) {
        return 'below';
    }

    if (accredited > contract + tol) {
        return 'above';
    }

    return 'equal';
}

/** % otorgado en el cupo, con color respecto al % esperado del mismo período. */
function AccreditedPercentVsPlan({
    accreditedPct,
    expectedPct,
}: {
    accreditedPct: number;
    expectedPct: number;
}) {
    const rel = compareAccruedVsContract(accreditedPct, expectedPct);

    const formatted = `${accreditedPct.toLocaleString('es-US', {
        minimumFractionDigits: 0,
        maximumFractionDigits: 4,
    })}%`;

    return (
        <span
            className={cn(
                'inline-flex items-center gap-1 font-semibold tabular-nums',
                rel === 'below' && 'text-red-600 dark:text-red-400',
                rel === 'above' && 'text-emerald-600 dark:text-emerald-400',
                rel === 'equal' && 'text-foreground',
            )}
        >
            {rel === 'below' ? (
                <TrendingDown
                    aria-hidden
                    className="size-3.5 shrink-0 opacity-95"
                    strokeWidth={2.25}
                />
            ) : null}
            {rel === 'above' ? (
                <TrendingUp
                    aria-hidden
                    className="size-3.5 shrink-0 opacity-95"
                    strokeWidth={2.25}
                />
            ) : null}
            <span>{formatted}</span>
            <span className="sr-only">
                {rel === 'below'
                    ? ', por debajo del porcentaje pactado en el plan.'
                    : rel === 'above'
                      ? ', por encima del porcentaje pactado en el plan.'
                      : ', igual al porcentaje pactado en el plan.'}
            </span>
        </span>
    );
}

function InvestmentRowDetail({
    investment: inv,
}: {
    investment: UserPortfolioInvestment;
}) {
    const perf = inv.month_performance ?? [];

    const chartData = useMemo((): MonthChartPoint[] => {
        return perf.map((m: InvestmentMonthPerf): MonthChartPoint => {
            const projectedRaw =
                typeof m.projected_gain_usd === 'number'
                    ? m.projected_gain_usd
                    : Number.parseFloat(
                          String(m.projected_gain_usd ?? '').replace(',', '.'),
                      );
            const safeProjected =
                Number.isFinite(projectedRaw) && projectedRaw >= 0 ? projectedRaw : 0;

            let actualUsd: number | null = null;
            if (
                m.actual_gain_usd !== null &&
                m.actual_gain_usd !== undefined
            ) {
                const raw =
                    typeof m.actual_gain_usd === 'number'
                        ? m.actual_gain_usd
                        : Number.parseFloat(
                              String(m.actual_gain_usd).replace(',', '.'),
                          );
                if (Number.isFinite(raw)) {
                    actualUsd = raw;
                }
            }

            return {
                label:
                    m.period_label?.trim() ||
                    `Mes ${m.month_index}`,
                projectedUsd: safeProjected,
                actualUsd,
            };
        });
    }, [perf]);

    const planPct = Number(inv.monthly_return_snapshot);
    const pctFormatted = `${planPct.toLocaleString('es-US', {
        minimumFractionDigits: 0,
        maximumFractionDigits: 4,
    })}%`;

    return (
        <div className="space-y-6">
            <div className="grid gap-2 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-7">
                <DetailStatMini title="Contrato (% mensual)" value={pctFormatted} />
                <DetailStatMini title="Principal" value={formatCurrency(Number(inv.amount))} />
                <DetailStatMini
                    title={inv.status === 'pending' ? 'Capital (pendiente)' : 'Capital vigente'}
                    value={
                        inv.status === 'pending'
                            ? formatCurrency(Number(inv.amount))
                            : formatCurrency(Number(inv.current_capital_usd))
                    }
                />
                <DetailStatMini
                    title="Acreditaciones"
                    value={
                        <MonthlyAccrualsProgress
                            durationMonths={inv.duration_months}
                            monthsCredited={inv.months_credited}
                            pending={inv.status === 'pending'}
                        />
                    }
                />
                <DetailStatMini
                    title="Ganancia día pactada (referencia)"
                    value={formatCurrency(Number(inv.projected_daily_gain))}
                />
                <DetailStatMini
                    title="Ganancia mensual equivalente (plan)"
                    value={formatCurrency(Number(inv.projected_monthly_gain))}
                />
                <DetailStatMini
                    title="Ganancia total pactada"
                    value={formatCurrency(Number(inv.projected_total_gain))}
                />
            </div>

            {inv.status !== 'pending' && (
                <div className="flex flex-wrap justify-end gap-2">
                    <Button asChild size="sm" variant="secondary">
                        <Link href="/balances">
                            <Landmark className="size-4" />
                            Retiros y balance consolidado
                        </Link>
                    </Button>
                    <Button asChild size="sm" variant="outline">
                        <Link href={`/mis-inversiones/${inv.id}/movimientos`}>
                            <ListTree className="size-4" />
                            Ver movimientos (depósitos, ganancias, retiros)
                        </Link>
                    </Button>
                </div>
            )}

            <div className="rounded-lg border bg-card px-4 py-4">
                <p className="mb-4 text-base font-semibold">
                    Comparativa por mes contractual (plan pactado vs acumulado diario)
                </p>
                {inv.status === 'pending' ? (
                    <p className="text-sm text-muted-foreground">
                        Tus acreditaciones aparecerán aquí después de confirmar el pago. La acreditación es diaria y automática
                        según el porcentaje mensual de tu plan.
                    </p>
                ) : (
                    <>
                        <MonthlyGainsChart data={chartData} />
                        <MonthlyAccreditedBreakdown perf={perf} />
                    </>
                )}
            </div>
        </div>
    );
}

/** Tabla mes a mes: capital base ese mes y acreditación global. */
function MonthlyAccreditedBreakdown({
    perf,
}: {
    perf: InvestmentMonthPerf[];
}) {
    if (perf.length === 0) {
        return null;
    }

    return (
        <div className="mt-6 overflow-x-auto rounded-md border bg-background/50">
            <table className="w-full min-w-[680px] text-left text-sm">
                <caption className="sr-only">
                    Detalle mensual por acreditación contractual: capital base y % global
                    acreditado por la administración
                </caption>
                <thead>
                    <tr className="border-b bg-muted/30 text-muted-foreground">
                        <th className="px-3 py-2.5 font-medium">Período</th>
                        <th className="px-3 py-2.5 font-medium tabular-nums">
                            Capital antes del %
                        </th>
                        <th className="px-3 py-2.5 font-medium tabular-nums">
                            % plan
                        </th>
                        <th className="px-3 py-2.5 font-medium tabular-nums">
                            Ganancia proyectada
                        </th>
                        <th className="px-3 py-2.5 font-medium tabular-nums">
                            Rend. vs esperado *
                        </th>
                        <th className="px-3 py-2.5 font-medium tabular-nums text-primary">
                            Ganancia acreditada
                        </th>
                    </tr>
                </thead>
                <tbody className="divide-y">
                    {perf.map((m) => {
                        const projected = parseUsdField(m.projected_gain_usd);
                        const nominal =
                            typeof m.nominal_percent === 'number' &&
                            Number.isFinite(m.nominal_percent)
                                ? m.nominal_percent
                                : NaN;

                        const capitalBase =
                            m.capital_base_usd !== null &&
                            m.capital_base_usd !== undefined
                                ? parseUsdField(m.capital_base_usd)
                                : null;

                        let accreditedPct: number | null = null;
                        const rawAccredited = m.accredited_percent;
                        if (
                            rawAccredited !== null &&
                            rawAccredited !== undefined &&
                            typeof rawAccredited === 'number' &&
                            Number.isFinite(rawAccredited)
                        ) {
                            accreditedPct = rawAccredited;
                        }

                        let expectedPeriodPct: number | null = null;
                        const rawExpectedPeriod = m.expected_period_percent;
                        if (
                            rawExpectedPeriod !== null &&
                            rawExpectedPeriod !== undefined &&
                            typeof rawExpectedPeriod === 'number' &&
                            Number.isFinite(rawExpectedPeriod)
                        ) {
                            expectedPeriodPct = rawExpectedPeriod;
                        } else if (
                            capitalBase !== null &&
                            capitalBase > 0 &&
                            projected >= 0.01
                        ) {
                            expectedPeriodPct =
                                Math.round((projected / capitalBase) * 10000) / 10000;
                        }

                        const actualGainParsed = parseUsdField(m.actual_gain_usd);
                        const hasAccreditedGain = actualGainParsed >= 0.01;
                        const isSkipped = m.is_skipped === true;
                        const isExtension = m.is_extension === true;

                        const periodEnded =
                            m.period_end !== undefined &&
                            m.period_end !== '' &&
                            (() => {
                                const end = new Date(`${m.period_end}T12:00:00`);
                                const today = new Date();
                                today.setHours(12, 0, 0, 0);

                                return (
                                    !Number.isNaN(end.getTime()) && end.getTime() < today.getTime()
                                );
                            })();

                        return (
                            <tr
                                key={m.month_index}
                                className={cn(isSkipped && 'text-muted-foreground')}
                            >
                                <td
                                    className={cn(
                                        'px-3 py-2.5 font-medium',
                                        isSkipped && 'line-through',
                                    )}
                                >
                                    {m.period_label?.trim() || `Mes ${m.month_index}`}
                                </td>
                                <td
                                    className={cn(
                                        'px-3 py-2.5 tabular-nums',
                                        isSkipped && 'line-through',
                                    )}
                                >
                                    {capitalBase !== null ? (
                                        formatCurrency(capitalBase)
                                    ) : (
                                        <span className="text-muted-foreground">
                                            —
                                        </span>
                                    )}
                                </td>
                                <td
                                    className={cn(
                                        'px-3 py-2.5 tabular-nums text-muted-foreground',
                                        isSkipped && 'line-through',
                                    )}
                                >
                                    {Number.isFinite(nominal)
                                        ? `${nominal.toLocaleString('es-US', {
                                              minimumFractionDigits: 0,
                                              maximumFractionDigits: 4,
                                          })}%`
                                        : '—'}
                                </td>
                                <td
                                    className={cn(
                                        'px-3 py-2.5 tabular-nums',
                                        isSkipped && 'line-through',
                                    )}
                                >
                                    {formatCurrency(projected)}
                                </td>
                                <td
                                    className={cn(
                                        'px-3 py-2.5 tabular-nums',
                                        isSkipped && 'line-through',
                                    )}
                                >
                                    {expectedPeriodPct !== null &&
                                    (accreditedPct !== null ||
                                        (!hasAccreditedGain &&
                                            projected >= 0.01 &&
                                            periodEnded)) ? (
                                        <AccreditedPercentVsPlan
                                            accreditedPct={accreditedPct ?? 0}
                                            expectedPct={expectedPeriodPct}
                                        />
                                    ) : accreditedPct !== null ? (
                                        <span className="font-semibold tabular-nums">
                                            {accreditedPct.toLocaleString('es-US', {
                                                minimumFractionDigits: 0,
                                                maximumFractionDigits: 4,
                                            })}
                                            %
                                        </span>
                                    ) : isSkipped ? (
                                        <span className="font-normal italic">
                                            Anulado
                                        </span>
                                    ) : (
                                        <span className="font-normal text-muted-foreground">
                                            Pendiente
                                        </span>
                                    )}
                                </td>
                                <td
                                    className={cn(
                                        'px-3 py-2.5 tabular-nums font-medium',
                                        isSkipped && 'line-through',
                                    )}
                                >
                                    {hasAccreditedGain ? (
                                        formatCurrency(actualGainParsed)
                                    ) : (
                                        <span className="font-normal text-muted-foreground">
                                            —
                                        </span>
                                    )}
                                </td>
                            </tr>
                        );
                    })}
                </tbody>
            </table>
        </div>
    );
}

function parseUsdField(value: string | number | undefined | null): number {
    if (typeof value === 'number' && Number.isFinite(value)) {
        return value;
    }
    const n = Number.parseFloat(String(value ?? '').replace(',', '.'));
    return Number.isFinite(n) ? n : 0;
}

function formatIsoDate(value: string | null): string {
    if (!value) {
        return '-';
    }
    return new Date(value).toLocaleDateString('es', { dateStyle: 'medium' });
}
