import { Button, Card } from '@/Components/ui';
import { cn } from '@/lib/cn';
import { Link } from '@inertiajs/react';
import { Check } from 'lucide-react';
import type { ReactNode } from 'react';
import type { CurrencyRow, CurrentSubscription, Period, PlanRow } from './types';

type Props = {
    plan: PlanRow;
    /** amount_minor for selected (currency, period); null if no active price (Free or unsupported). */
    amountMinor: number | null;
    /** Equivalent yearly amount used for "save X% vs monthly" copy. */
    yearlyAmountMinor: number | null;
    monthlyAmountMinor: number | null;
    currency: CurrencyRow;
    period: Period;
    isAuthed: boolean;
    currentSubscription: CurrentSubscription | null;
    /** Whether at least one gateway is available for this (plan, currency, period). */
    hasGateways: boolean;
    /** Open the gateway-picker modal for this plan. Async because the
     *  fast-path skips the modal and POSTs /checkout directly. */
    onChoose: () => void | Promise<void>;
    /** Set true while a single-gateway fast-path checkout is in flight
     *  (POST /checkout → redirect). The CTA renders a spinner so the
     *  user has visual feedback during the round-trip. */
    pending?: boolean;
};

// Override badge label per plan key. Defaults to "Most popular" when
// missing — applied to the featured (`pro`) plan only.
const FEATURED_TAGLINE: Record<string, string> = {
    pro: 'Most popular',
};

function formatAmount(amountMinor: number, currency: CurrencyRow): string {
    const major = amountMinor / 100;
    const isWhole = major % 1 === 0;
    // INR uses Indian grouping (1,00,000); everything else uses en-US grouping.
    const locale = currency.code === 'INR' ? 'en-IN' : 'en-US';
    const body = major.toLocaleString(locale, {
        minimumFractionDigits: isWhole ? 0 : 2,
        maximumFractionDigits: 2,
    });
    return `${currency.symbol}${body}`;
}

function bulletsFor(plan: PlanRow): string[] {
    const bullets: string[] = [];
    if (plan.project_limit === null || plan.project_limit === undefined) {
        bullets.push('Unlimited projects');
    } else {
        bullets.push(`${plan.project_limit} projects`);
    }
    bullets.push(plan.can_export ? 'Export enabled' : 'All editor features (no export)');
    if (plan.storage_bytes_limit === null || plan.storage_bytes_limit === undefined) {
        bullets.push('Unlimited storage');
    } else {
        bullets.push(`${formatBytes(plan.storage_bytes_limit)} storage`);
    }
    // Team seat cap — owner + admins + editors (viewers are always free +
    // unlimited). null = unlimited members; undefined = caller omitted it.
    if (plan.max_seats === null) {
        bullets.push('Unlimited members + viewers');
    } else if (typeof plan.max_seats === 'number') {
        bullets.push(
            plan.max_seats === 1
                ? 'Single member'
                : `${plan.max_seats} members + unlimited viewers`,
        );
    }
    const f = plan.features ?? {};
    bullets.push(f.can_use_premium_kits ? 'Premium templates' : 'Templates');
    if (f.can_use_ai) {
        bullets.push('AI generation');
        bullets.push(
            f.ai_tokens_monthly === null || f.ai_tokens_monthly === undefined
                ? 'Unlimited AI tokens'
                : `${Number(f.ai_tokens_monthly).toLocaleString()} AI tokens`,
        );
    }
    return bullets;
}

function formatBytes(bytes: number): string {
    if (!Number.isFinite(bytes) || bytes <= 0) return '0 KB';
    const GB = 1024 * 1024 * 1024;
    const MB = 1024 * 1024;
    const KB = 1024;
    const fmt = (n: number) =>
        n % 1 === 0 ? n.toString() : n.toFixed(1).replace(/\.0$/, '');
    if (bytes >= GB) return `${fmt(bytes / GB)} GB`;
    if (bytes >= MB) return `${fmt(bytes / MB)} MB`;
    if (bytes >= KB) return `${fmt(bytes / KB)} KB`;
    return `${bytes} B`;
}

function yearlyDiscountPct(monthly: number, yearly: number): number {
    if (monthly <= 0 || yearly <= 0) return 0;
    const fullYear = monthly * 12;
    if (yearly >= fullYear) return 0;
    return Math.round((1 - yearly / fullYear) * 100);
}

export default function PlanCard({
    plan,
    amountMinor,
    yearlyAmountMinor,
    monthlyAmountMinor,
    currency,
    period,
    isAuthed,
    currentSubscription,
    hasGateways,
    onChoose,
    pending = false,
}: Props) {
    const isFree = plan.key === 'free';
    const featured = plan.key === 'pro';
    const tagline = FEATURED_TAGLINE[plan.key] ?? 'Most popular';
    const bullets = bulletsFor(plan);

    const discountPct =
        monthlyAmountMinor !== null && yearlyAmountMinor !== null
            ? yearlyDiscountPct(monthlyAmountMinor, yearlyAmountMinor)
            : 0;

    const isCurrentExact =
        currentSubscription?.plan_key === plan.key &&
        currentSubscription?.period === period &&
        // Currency match: subscriber's currency_id must equal the displayed
        // currency. If the user lands on /pricing?switch_provider=1 we don't
        // see currentSubscription at all, so this just behaves like a fresh signup.
        currentSubscription?.currency_id === currency.id;

    return (
        <Card
            padding="lg"
            className={cn(
                'ms-plan-card flex flex-col',
                featured && 'border-accent/40 shadow-md',
            )}
            data-testid={`pricing-card-${plan.key}`}
        >
            <div className="flex items-center justify-between gap-3">
                <h3 className="text-2xl font-semibold tracking-tight text-foreground">
                    {plan.name}
                </h3>
                {featured && (
                    <span className="ms-popular-badge rounded-full border border-accent/30 bg-accent/5 px-2.5 py-0.5 text-[10px] font-medium text-accent">
                        {tagline}
                    </span>
                )}
            </div>

            {plan.description && (
                <p className="mt-2 text-sm text-muted-foreground">{plan.description}</p>
            )}

            <div className="mt-6">
                {isFree || amountMinor === null ? (
                    <div className="flex items-baseline gap-2">
                        <span className="text-4xl font-semibold tracking-tight text-foreground">
                            {isFree ? 'Free' : '—'}
                        </span>
                        {!isFree && (
                            <span className="text-sm text-muted-foreground">
                                Not available in {currency.code}
                            </span>
                        )}
                    </div>
                ) : (
                    <>
                        <div className="flex items-baseline gap-2">
                            <span className="text-4xl font-semibold tracking-tight text-foreground">
                                {formatAmount(amountMinor, currency)}
                            </span>
                            <span className="text-sm text-muted-foreground">
                                / {period === 'yearly' ? 'year' : 'month'}
                            </span>
                        </div>
                        {period === 'yearly' && discountPct > 0 && (
                            <p className="mt-1 text-xs text-accent">
                                Save {discountPct}% vs monthly
                            </p>
                        )}
                        {period === 'monthly' && yearlyAmountMinor !== null && (
                            <p className="mt-1 text-xs text-muted-foreground">
                                or {formatAmount(yearlyAmountMinor, currency)}/year
                                {discountPct > 0 && (
                                    <span className="ml-1 text-accent">
                                        ({discountPct}% off)
                                    </span>
                                )}
                            </p>
                        )}
                    </>
                )}
            </div>

            <ul className="mt-6 flex flex-1 flex-col gap-2.5">
                {bullets.map((b) => (
                    <Bullet key={b}>{b}</Bullet>
                ))}
            </ul>

            <div className="mt-6">
                <PlanCta
                    plan={plan}
                    isFree={isFree}
                    isAuthed={isAuthed}
                    hasGateways={hasGateways}
                    isCurrentExact={isCurrentExact}
                    isSubscribed={currentSubscription !== null}
                    onChoose={onChoose}
                    pending={pending}
                />
            </div>
        </Card>
    );
}

function Bullet({ children }: { children: ReactNode }) {
    return (
        <li className="flex items-start gap-2 text-sm text-foreground/80">
            <Check
                className="ms-check mt-0.5 h-4 w-4 shrink-0 text-accent"
                strokeWidth={2.5}
                aria-hidden
            />
            <span>{children}</span>
        </li>
    );
}

function PlanCta({
    plan,
    isFree,
    isAuthed,
    hasGateways,
    isCurrentExact,
    isSubscribed,
    onChoose,
    pending,
}: {
    plan: PlanRow;
    isFree: boolean;
    isAuthed: boolean;
    hasGateways: boolean;
    isCurrentExact: boolean;
    isSubscribed: boolean;
    onChoose: () => void | Promise<void>;
    pending: boolean;
}) {
    if (isCurrentExact) {
        return (
            <Button variant="secondary" disabled className="w-full">
                Current plan
            </Button>
        );
    }

    if (!isAuthed) {
        // Free → bare /register. Paid → carry intent so post-signup landing
        // can re-route to /pricing with the right plan teed up. The existing
        // billing-pricing-page spec asserts that paid plan CTAs link to
        // /register and contain `plan_pro`.
        return (
            <Link
                href={isFree ? '/register' : `/register?intent=plan_${plan.key}`}
                className="block"
            >
                <Button
                    variant={isFree ? 'secondary' : 'primary'}
                    className="w-full"
                >
                    {isFree ? 'Get started' : `Sign up for ${plan.name}`}
                </Button>
            </Link>
        );
    }

    if (isFree) {
        // Authed + sub'd looking at Free → that's a cancel (downgrade flow).
        if (isSubscribed) {
            return (
                <Link href="/account/subscription" className="block">
                    <Button variant="secondary" className="w-full">
                        Cancel to downgrade
                    </Button>
                </Link>
            );
        }
        return (
            <Button variant="secondary" disabled className="w-full">
                Included by default
            </Button>
        );
    }

    if (!hasGateways) {
        return (
            <Button
                variant="primary"
                disabled
                className="w-full"
                data-testid={`pricing-cta-${plan.key}`}
                title="No payment provider available for this currency + period"
            >
                {isSubscribed ? `Switch to ${plan.name}` : `Subscribe to ${plan.name}`}
            </Button>
        );
    }

    return (
        <Button
            variant="primary"
            className="w-full"
            onClick={() => void onChoose()}
            disabled={pending}
            data-testid={`pricing-cta-${plan.key}`}
        >
            {pending
                ? 'Redirecting…'
                : isSubscribed
                    ? `Switch to ${plan.name}`
                    : `Subscribe to ${plan.name}`}
        </Button>
    );
}
