import { useState, useEffect, useCallback } from 'react';
import { motion } from 'motion/react';
import { Check, ArrowRight, Zap, Loader2 } from 'lucide-react';
import { startCheckout, subscribeCheckoutPhase, type CheckoutPhase } from '../services/checkout';
import { t, tArray } from '../i18n';

// Static fallback from build-time generation (used while fetching live prices)
import fallbackTiers from '../generated/tiers.json';

interface Tier {
  name: string;
  localeKey?: string;
  description: string;
  features: string[];
  highlighted?: boolean;
  price?: number | null;
  period?: string;
  monthlyPrice?: number;
  annualPrice?: number | null;
  cta?: string;
  href?: string;
  monthlyProductId?: string;
  annualProductId?: string;
}

const CATALOG_API = 'https://api.worldmonitor.app/api/product-catalog';

function usePricingData(): Tier[] {
  const [tiers, setTiers] = useState<Tier[]>(fallbackTiers as Tier[]);

  useEffect(() => {
    let cancelled = false;
    fetch(CATALOG_API, { signal: AbortSignal.timeout(5000) })
      .then(res => res.ok ? res.json() : null)
      .then(data => {
        if (!cancelled && data?.tiers?.length) {
          setTiers(data.tiers as Tier[]);
        }
      })
      .catch(() => { /* keep fallback */ });
    return () => { cancelled = true; };
  }, []);

  return tiers;
}

/**
 * Look up localized copy for a catalog tier, falling back to the catalog
 * value when the locale hasn't translated this tier yet. Generated tiers
 * carry a stable localeKey so display-name changes do not affect lookup.
 */
function localizeTier(tier: Tier): { description: string; features: string[]; cta?: string } {
  const key = tier.localeKey ?? tier.name.toLowerCase();
  const description = t(`pricing.tiers.${key}.description`, { defaultValue: tier.description });
  const features = tArray(`pricing.tiers.${key}.features`) ?? tier.features;
  // Resolve CTA priority: locale-specific tier override → catalog tier.cta →
  // undefined (so getCtaProps applies the generic localized fallback). The
  // SENTINEL trick lets us detect "key missing" vs "key resolves to empty".
  const SENTINEL = '__no_locale_cta__';
  const localeCta = t(`pricing.tiers.${key}.cta`, { defaultValue: SENTINEL });
  const cta = localeCta !== SENTINEL ? localeCta : tier.cta;
  return { description, features, cta };
}

function formatPrice(tier: Tier, billing: 'monthly' | 'annual'): { amount: string; suffix: string } {
  // Free tier
  if (tier.price === 0) {
    return { amount: "$0", suffix: t('pricing.suffixForever') };
  }
  // Enterprise / custom
  if (tier.price === null && tier.monthlyPrice === undefined) {
    return { amount: t('pricing.amountCustom'), suffix: t('pricing.suffixTailored') };
  }
  // API tier (monthly only)
  if (tier.annualPrice === null && tier.monthlyPrice !== undefined) {
    return { amount: `$${tier.monthlyPrice}`, suffix: t('pricing.suffixPerMonth') };
  }
  // Pro tier with toggle
  if (billing === 'annual' && tier.annualPrice != null) {
    return { amount: `$${tier.annualPrice}`, suffix: t('pricing.suffixPerYear') };
  }
  return { amount: `$${tier.monthlyPrice}`, suffix: t('pricing.suffixPerMonth') };
}

type CtaProps =
  | { type: 'link'; label: string; href: string; external: boolean }
  | { type: 'checkout'; label: string; productId: string };

/**
 * Is this href pointing back at our own product surface (so a
 * same-tab navigation is the natural UX), or to something genuinely
 * off-platform (mailto, external docs) where a new tab is preferred?
 *
 * Anchors (`#pricing`) and relative paths are treated as in-product.
 * `mailto:` / `tel:` and any other-origin http(s) URLs are external.
 */
function isInProductHref(href: string): boolean {
  if (!href || href === '#' || href.startsWith('#')) return true;
  // Exclude protocol-relative URLs (//cdn.evilhost.com/x) — they LOOK
  // like leading-slash paths but browsers resolve them to a different
  // origin. Only true absolute paths (`/foo`, `/foo/bar`) are in-product.
  if (href.startsWith('/') && !href.startsWith('//')) return true;
  // Catch relative paths without a leading slash: `pricing`, `./dashboard`,
  // `../foo`. `new URL('pricing')` throws without a base — those were
  // hitting the catch branch below and being misclassified as external.
  // Resolve against the current origin to determine whether the result
  // lands on our product surface.
  const looksRelative = !/^[a-z][a-z0-9+.-]*:/i.test(href) && !href.startsWith('//');
  try {
    const base = typeof window !== 'undefined' ? window.location.href : 'https://worldmonitor.app/';
    const url = new URL(href, looksRelative ? base : undefined);
    if (url.protocol !== 'http:' && url.protocol !== 'https:') return false;
    return url.hostname === 'worldmonitor.app' ||
           url.hostname.endsWith('.worldmonitor.app') ||
           // localhost dev-server case so relative CTAs work in pro-test
           url.hostname === 'localhost' ||
           url.hostname === '127.0.0.1';
  } catch {
    return false;
  }
}

function getCtaProps(tier: Tier, billing: 'monthly' | 'annual'): CtaProps {
  if (tier.cta && tier.href && tier.price === 0) {
    // Free tier on an in-product href (e.g. worldmonitor.app dashboard)
    // should open in-place. Only send to a new tab when the href is
    // genuinely off-platform (unusual for free tier but possible).
    return {
      type: 'link',
      label: tier.cta,
      href: tier.href,
      external: !isInProductHref(tier.href),
    };
  }
  if (tier.cta && tier.href && tier.price === null) {
    // Enterprise is typically `mailto:` → external remains true so the
    // OS mail client opens in its own window. Any hypothetical in-
    // product enterprise href would navigate same-tab instead.
    return {
      type: 'link',
      label: tier.cta,
      href: tier.href,
      external: !isInProductHref(tier.href),
    };
  }
  if (tier.monthlyProductId) {
    const productId = (billing === 'annual' && tier.annualProductId) ? tier.annualProductId : tier.monthlyProductId;
    // Honor per-tier CTA text from the catalog (e.g. "Start Pro",
    // "Subscribe") when present; fall back to a localized generic label
    // so paid checkout buttons aren't English-only on non-English locales.
    return { type: 'checkout', label: tier.cta ?? t('pricing.cta.checkoutDefault'), productId };
  }
  return { type: 'link', label: t('pricing.cta.learnMore'), href: '#', external: false };
}

export function PricingSection({ refCode }: { refCode?: string }) {
  const [billing, setBilling] = useState<'monthly' | 'annual'>('monthly');
  // Loading state is driven by the service's checkout phase. Only the
  // `creating_checkout` phase (post-auth, inside doCheckout) disables
  // the clicked CTA. During the Clerk modal window, phase stays idle —
  // the modal backdrop is the user's feedback, so locking the pricing
  // section underneath adds no value and creates recovery problems
  // (watchdogs, DOM polling) that we don't need.
  const [phase, setPhase] = useState<CheckoutPhase>({ kind: 'idle' });
  const loadingProductId = phase.kind === 'creating_checkout' ? phase.productId : null;
  const TIERS = usePricingData();

  useEffect(() => subscribeCheckoutPhase(setPhase), []);

  // checkoutInFlight in the service guards concurrent doCheckout runs.
  // The handler is fire-and-forget — no local loading state to manage.
  const handleCheckout = useCallback((productId: string) => {
    void startCheckout(productId, { referralCode: refCode });
  }, [refCode]);

  return (
    <section id="pricing" className="py-24 px-6 border-t border-wm-border bg-[#060606]">
      <div className="max-w-7xl mx-auto">
        {/* Header */}
        <div className="text-center mb-16">
          <motion.h2
            className="text-3xl md:text-5xl font-display font-bold mb-4"
            initial={{ opacity: 0, y: 20 }}
            whileInView={{ opacity: 1, y: 0 }}
            viewport={{ once: true }}
            transition={{ duration: 0.5 }}
          >
            {t('pricing.headerTitle')}
          </motion.h2>
          <motion.p
            className="text-wm-muted max-w-xl mx-auto mb-8"
            initial={{ opacity: 0, y: 10 }}
            whileInView={{ opacity: 1, y: 0 }}
            viewport={{ once: true }}
            transition={{ duration: 0.5, delay: 0.1 }}
          >
            {t('pricing.headerSubtitle')}
          </motion.p>

          {/* Billing toggle — disabled while a checkout is active.
              Switching billing mid-flight would change cta.productId
              out from under the active checkout, making the spinner
              vanish from the tier the user clicked. Locking the toggle
              during the flow is the simplest correct behavior: the
              user committed to a plan by clicking Checkout. */}
          <motion.div
            className="inline-flex items-center gap-3 bg-wm-card border border-wm-border rounded-sm p-1"
            initial={{ opacity: 0, y: 10 }}
            whileInView={{ opacity: 1, y: 0 }}
            viewport={{ once: true }}
            transition={{ duration: 0.5, delay: 0.2 }}
          >
            <button
              onClick={() => setBilling('monthly')}
              disabled={loadingProductId !== null}
              className={`px-4 py-2 rounded-sm font-mono text-xs uppercase tracking-wider transition-colors disabled:cursor-not-allowed disabled:opacity-60 ${
                billing === 'monthly'
                  ? 'bg-wm-green text-wm-bg font-bold'
                  : 'text-wm-muted hover:text-wm-text'
              }`}
            >
              {t('pricing.billingMonthly')}
            </button>
            <button
              onClick={() => setBilling('annual')}
              disabled={loadingProductId !== null}
              className={`px-4 py-2 rounded-sm font-mono text-xs uppercase tracking-wider transition-colors flex items-center gap-2 disabled:cursor-not-allowed disabled:opacity-60 ${
                billing === 'annual'
                  ? 'bg-wm-green text-wm-bg font-bold'
                  : 'text-wm-muted hover:text-wm-text'
              }`}
            >
              {/* Lock billing toggle ONLY during creating_checkout (narrow
                  post-auth window). Through the Clerk modal the toggle
                  is covered by the backdrop anyway; locking during the
                  modal was unnecessary. */}
              {t('pricing.billingAnnual')}
              <span className={`text-[10px] px-1.5 py-0.5 rounded-sm ${
                billing === 'annual'
                  ? 'bg-wm-bg/20 text-wm-bg'
                  : 'bg-wm-green/10 text-wm-green'
              }`}>
                {t('pricing.saveAnnual')}
              </span>
            </button>
          </motion.div>
        </div>

        {/* Tier cards grid */}
        <div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-6">
          {TIERS.map((tier, i) => {
            const price = formatPrice(tier, billing);
            const localized = localizeTier(tier);
            // Build a localized tier shape so getCtaProps picks the right
            // CTA label per locale (link CTAs read tier.cta directly).
            const localizedTier: Tier = { ...tier, cta: localized.cta };
            const cta = getCtaProps(localizedTier, billing);

            return (
              <motion.div
                key={tier.name}
                className={`relative bg-zinc-900 rounded-lg p-6 flex flex-col ${
                  tier.highlighted
                    ? 'border-2 border-wm-green shadow-lg shadow-wm-green/10'
                    : 'border border-wm-border'
                }`}
                initial={{ opacity: 0, y: 30 }}
                whileInView={{ opacity: 1, y: 0 }}
                viewport={{ once: true }}
                transition={{ duration: 0.5, delay: i * 0.1 }}
              >
                {/* Most Popular badge */}
                {tier.highlighted && (
                  <div className="absolute -top-3 left-1/2 -translate-x-1/2 inline-flex items-center gap-1 bg-wm-green text-wm-bg px-3 py-1 rounded-full text-xs font-mono font-bold uppercase tracking-wider">
                    <Zap className="w-3 h-3" aria-hidden="true" />
                    {t('pricing.mostPopular')}
                  </div>
                )}

                {/* Tier name */}
                <h3 className={`font-display text-lg font-bold mb-1 ${
                  tier.highlighted ? 'text-wm-green' : 'text-wm-text'
                }`}>
                  {tier.name}
                </h3>

                {/* Description */}
                <p className="text-xs text-wm-muted mb-4">{localized.description}</p>

                {/* Price */}
                <div className="mb-6">
                  <span className="text-4xl font-display font-bold">{price.amount}</span>
                  <span className="text-sm text-wm-muted ml-1">{price.suffix}</span>
                </div>

                {/* Features */}
                <ul className="space-y-3 mb-8 flex-1">
                  {localized.features.map((feature, fi) => (
                    <li key={fi} className="flex items-start gap-2 text-sm">
                      <Check className={`w-4 h-4 shrink-0 mt-0.5 ${
                        tier.highlighted ? 'text-wm-green' : 'text-wm-muted'
                      }`} aria-hidden="true" />
                      <span className="text-wm-muted">{feature}</span>
                    </li>
                  ))}
                </ul>

                {/* CTA button */}
                {cta.type === 'link' ? (
                  <a
                    href={cta.href}
                    target={cta.external ? "_blank" : undefined}
                    rel={cta.external ? "noreferrer" : undefined}
                    className={`block text-center py-3 rounded-sm font-mono text-xs uppercase tracking-wider font-bold transition-colors ${
                      tier.highlighted
                        ? 'bg-wm-green text-wm-bg hover:bg-green-400'
                        : 'border border-wm-border text-wm-muted hover:text-wm-text hover:border-wm-text'
                    }`}
                  >
                    {cta.label} <ArrowRight className="w-3.5 h-3.5 inline-block ml-1" aria-hidden="true" />
                  </a>
                ) : (() => {
                  const isLoading = loadingProductId === cta.productId;
                  // Only the clicked tier disables during creating_checkout.
                  // Sibling tiers stay clickable; if the user changes their
                  // mind mid-flow, their next click simply updates the
                  // pending intent. The pricing page is never hard-locked.
                  return (
                    <button
                      onClick={() => handleCheckout(cta.productId)}
                      disabled={isLoading}
                      aria-busy={isLoading || undefined}
                      className={`block w-full text-center py-3 rounded-sm font-mono text-xs uppercase tracking-wider font-bold transition-colors ${
                        isLoading ? 'cursor-wait opacity-70' : 'cursor-pointer'
                      } ${
                        tier.highlighted
                          ? 'bg-wm-green text-wm-bg hover:bg-green-400'
                          : 'border border-wm-border text-wm-muted hover:text-wm-text hover:border-wm-text'
                      }`}
                    >
                      {isLoading ? (
                        <>
                          <Loader2 className="w-3.5 h-3.5 inline-block mr-2 animate-spin" aria-hidden="true" />
                          <span>{t('pricing.opening')}</span>
                        </>
                      ) : (
                        <>
                          {cta.label} <ArrowRight className="w-3.5 h-3.5 inline-block ml-1" aria-hidden="true" />
                        </>
                      )}
                    </button>
                  );
                })()}
              </motion.div>
            );
          })}
        </div>

        {/* Discount code note */}
        <p className="text-center text-xs text-wm-muted font-mono mt-8">
          {t('pricing.promoCodeNote')}
        </p>
      </div>
    </section>
  );
}
