// Billing & plans screen — current plan, plan comparison, upgrade / cancel.
const BILLING_ACCENT = { free: "var(--muted)", pro: "var(--green)", enterprise: "var(--cyan)" };

/** Headline limit shown on a plan card. */
function planHeadline(plan) {
  // Pro: per-minute burst is the active ceiling (no daily cap). Free: daily.
  if (plan.daily_limit == null && plan.burst_limit_per_min != null) {
    return Fmt.num(plan.burst_limit_per_min) + " credits / minute";
  }
  return Fmt.num(plan.daily_limit) + " credits / day";
}

function billingFeatures(plan) {
  // The "Up to 60s delay" line is the same on every tier — it's a product
  // characteristic, not a tier feature. Including it on each plan card keeps
  // the trade-off visible at the exact moment someone is choosing a plan.
  if (plan.id === "pro") {
    return [
      Fmt.num(plan.burst_limit_per_min || 10000) + " credits / minute",
      "Unlimited daily credits",
      "All 5 options endpoints",
      "Top 100 underlyings",
      "Up to 60s data delay",
      "Usage analytics",
      "Email support",
    ];
  }
  return [
    Fmt.num(plan.daily_limit || 1000) + " credits / day",
    Fmt.num(plan.burst_limit_per_min || 60) + " credits / minute burst",
    "All 5 options endpoints",
    "Top 100 underlyings",
    "Up to 60s data delay",
    "Community support",
  ];
}

function BillingStatusPill({ status }) {
  const map = {
    active: ["var(--green)", "var(--green-soft)", "Active"],
    pending: ["var(--amber)", "var(--amber-soft)", "Pending"],
    canceling: ["var(--amber)", "var(--amber-soft)", "Cancels at period end"],
    canceled: ["var(--muted)", "var(--panel-2)", "Canceled"],
    failed: ["var(--red)", "rgba(229,72,77,0.12)", "Payment failed"],
  };
  const m = map[status] || ["var(--muted)", "var(--panel-2)", status || "—"];
  return (
    <span className="mono text-xs" style={{
      padding: "2px 8px", borderRadius: 5, color: m[0], background: m[1],
    }}>{m[2]}</span>
  );
}

function BillingNotice({ notice, onDismiss }) {
  if (!notice) return null;
  const tone = ({
    success: ["var(--green)", "var(--green-soft)"],
    error: ["var(--red)", "rgba(229,72,77,0.12)"],
    info: ["var(--cyan)", "var(--panel-2)"],
  })[notice.type] || ["var(--cyan)", "var(--panel-2)"];
  return (
    <div className="row" style={{
      gap: 10, padding: "11px 14px", borderRadius: 9, marginBottom: 18,
      border: "1px solid " + tone[0], background: tone[1], fontSize: 13,
    }}>
      <span style={{ color: tone[0], flex: "0 0 auto", display: "flex" }}>
        {notice.type === "error"
          ? <Icon.X style={{ width: 15, height: 15 }} />
          : <Icon.Check style={{ width: 15, height: 15 }} />}
      </span>
      <span style={{ flex: 1, color: "var(--text)" }}>{notice.text}</span>
      <button className="icon-btn" onClick={onDismiss}><Icon.X style={{ width: 12, height: 12 }} /></button>
    </div>
  );
}

function billingPlanButton(plan, isCurrent, hasActiveSub, isCanceling, busy, askUpgrade, askCancel) {
  const wide = { justifyContent: "center" };
  if (isCurrent) {
    // Pro card while a "canceling" subscription is in flight — show the
    // transition message instead of plain "Current plan".
    if (isCanceling && plan.id !== "free") {
      return <button className="btn" disabled style={wide}>Canceling at period end</button>;
    }
    return <button className="btn" disabled style={wide}>Current plan</button>;
  }
  if (!plan.available) {
    return <button className="btn" disabled style={wide}>Unavailable</button>;
  }
  if (plan.id === "free") {
    if (hasActiveSub) {
      return (
        <button className="btn" disabled={busy} style={wide} onClick={askCancel}>
          Switch to Free
        </button>
      );
    }
    // Already in the process of cancelling → Free is where they'll land
    // automatically when the paid period ends; no extra action needed.
    if (isCanceling) {
      return <button className="btn" disabled style={wide}>You'll move here automatically</button>;
    }
    return <button className="btn" disabled style={wide}>Free plan</button>;
  }
  if (hasActiveSub || isCanceling) {
    return (
      <button className="btn" disabled style={wide}
        title={isCanceling ? "Resubscribe will be available once your current period ends" : "Cancel your current plan before switching"}>
        {isCanceling ? "Available after period end" : "Cancel current plan first"}
      </button>
    );
  }
  return (
    <button className="btn btn-primary" disabled={busy} style={wide}
      onClick={() => askUpgrade(plan.id, plan.name)}>
      <Icon.Bolt style={{ width: 13, height: 13 }} /> Upgrade to {plan.name}
    </button>
  );
}

function BillingPage({ onNavigate }) {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");
  const [plans, setPlans] = useState([]);
  const [current, setCurrent] = useState(null);
  const [busy, setBusy] = useState(false);
  const [notice, setNotice] = useState(null);

  // Guard against setState after unmount — see dashboard.jsx for the pattern.
  const mountedRef = useRef(true);
  useEffect(() => () => { mountedRef.current = false; }, []);
  const load = () => {
    if (plans.length === 0) setLoading(true);
    setError("");
    return API.cached("/billing", 60 * 1000)
      .then((res) => {
        if (!mountedRef.current) return;
        setPlans(res.plans || []);
        setCurrent(res.current || null);
        setLoading(false);
      })
      .catch((err) => {
        if (!mountedRef.current) return;
        setError(err.message || "Could not load billing details.");
        setLoading(false);
        throw err;
      });
  };

  // Initial load, then handle a return from the payment provider.
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const flow = params.get("billing");
    const subId = params.get("subscription_id");
    const cleanUrl = () => {
      try {
        window.history.replaceState({}, "", window.location.pathname + "#billing");
      } catch (e) { /* ignore */ }
    };
    load()
      .then(() => {
        if (flow === "return" && subId) {
          setBusy(true);
          API.post("/billing/confirm", { subscription_id: subId })
            .then((res) => {
              setCurrent(res.current || null);
              API.invalidate("/billing");
              API.invalidate("/auth/me");
              API.invalidate("/usage");
              setNotice({ type: "success", text: "Payment confirmed — your new plan is active." });
              setBusy(false);
              cleanUrl();
            })
            .catch((err) => {
              setNotice({ type: "error", text: (err && err.message) || "We could not confirm your payment." });
              setBusy(false);
              cleanUrl();
            });
        } else if (flow === "cancel") {
          setNotice({ type: "info", text: "Checkout was canceled — no changes were made to your plan." });
          cleanUrl();
        }
      })
      .catch(() => { /* error screen already shown */ });
  }, []);

  if (loading) return <LoadingScreen crumbs={["Console", "Billing"]} />;
  if (error) return <ErrorScreen crumbs={["Console", "Billing"]} message={error} onRetry={load} />;

  const currentPlanId = (current && current.plan_id) || "free";
  const sub = current && current.subscription;
  const hasActiveSub = !!(sub && sub.status === "active");
  // "canceling" = user clicked Cancel; PayPal stops charging, but Pro
  // access stays until current_period_end. The cancel button hides, a
  // "Cancels on" label appears.
  const isCanceling = !!(sub && sub.status === "canceling");
  const currentPlan =
    plans.find((p) => p.id === currentPlanId) || plans.find((p) => p.id === "free") || null;

  const startUpgrade = (planId) => {
    if (busy) return;
    setBusy(true);
    setNotice(null);
    API.post("/billing/subscribe", { plan: planId })
      .then((res) => {
        if (res && res.approve_url) {
          window.location.href = res.approve_url;
        } else {
          setBusy(false);
          setNotice({ type: "error", text: "Could not start checkout. Please try again." });
        }
      })
      .catch((err) => {
        setBusy(false);
        setNotice({ type: "error", text: (err && err.message) || "Could not start checkout." });
      });
  };

  const doCancel = () => {
    if (busy) return;
    setBusy(true);
    setNotice(null);
    API.post("/billing/cancel")
      .then((res) => {
        setCurrent(res.current || null);
        // Caches that reflect plan / sub state are now stale.
        API.invalidate("/billing");
        API.invalidate("/auth/me");
        API.invalidate("/usage");
        setBusy(false);
        // Build the message from the actual server-returned subscription so
        // the date matches what the user is told over email.
        const newSub = res && res.current && res.current.subscription;
        const isCancelingNow = newSub && newSub.status === "canceling";
        const until = newSub && newSub.current_period_end
          ? new Date(newSub.current_period_end).toLocaleDateString("en-US",
              { month: "short", day: "numeric", year: "numeric" })
          : null;
        if (isCancelingNow && until) {
          setNotice({
            type: "info",
            text: `Your subscription was canceled. Pro access stays until ${until} — no further charges. You'll receive a confirmation email.`,
          });
        } else {
          setNotice({ type: "info", text: "Your subscription was canceled. You are back on the Free plan." });
        }
      })
      .catch((err) => {
        setBusy(false);
        setNotice({ type: "error", text: (err && err.message) || "Could not cancel the subscription." });
      });
  };

  // Plan changes run straight from the action — being signed in is enough,
  // no extra password step. The names are kept so the plan buttons and the
  // "Cancel subscription" button below don't need to change.
  const askUpgrade = (planId) => startUpgrade(planId);
  const askCancel = () => doCancel();

  return (
    <>
      <TopBar crumbs={["Console", "Billing"]} />
      <div className="page">
        <div className="page-head">
          <span className="eyebrow">Subscription</span>
          <h1 className="page-title">Billing &amp; plans</h1>
          <p className="page-sub">
            Manage your Market-Options subscription. Upgrades take effect immediately
            after checkout.
          </p>
        </div>

        <BillingNotice notice={notice} onDismiss={() => setNotice(null)} />

        {/* Current plan */}
        <div className="card" style={{ marginBottom: 20 }}>
          <div className="card-body">
            <div className="row" style={{ justifyContent: "space-between", flexWrap: "wrap", gap: 16 }}>
              <div>
                <div className="row gap-6" style={{ marginBottom: 6 }}>
                  <span className="eyebrow" style={{ margin: 0 }}>Current plan</span>
                  {sub && <BillingStatusPill status={sub.status} />}
                </div>
                <div style={{ fontSize: 26, fontWeight: 600, letterSpacing: "-0.02em" }}>
                  {currentPlan ? currentPlan.name : "Free"}
                </div>
                <div className="mono text-xs muted" style={{ marginTop: 4 }}>
                  {currentPlan ? planHeadline(currentPlan) : "1,000 credits / day"}
                  {currentPlan && currentPlan.price_usd > 0
                    ? " · $" + currentPlan.price_usd + " / month"
                    : " · no charge"}
                  {hasActiveSub && sub.current_period_end
                    ? " · renews " + Fmt.date(sub.current_period_end)
                    : ""}
                  {isCanceling && sub.current_period_end
                    ? " · access until " + Fmt.date(sub.current_period_end) + " · no further charges"
                    : ""}
                </div>
              </div>
              <div className="row gap-10">
                <button className="btn" onClick={() => onNavigate && onNavigate("analytics")}>
                  <Icon.Chart style={{ width: 14, height: 14 }} /> View usage
                </button>
                {hasActiveSub && (
                  <button className="btn" style={{ color: "var(--red)" }} disabled={busy}
                    onClick={askCancel}>
                    <Icon.X style={{ width: 13, height: 13 }} /> Cancel subscription
                  </button>
                )}
              </div>
            </div>
          </div>
        </div>

        {/* Plan comparison */}
        <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 16 }}>
          {plans.map((plan) => {
            const isCurrent = plan.id === currentPlanId;
            const accent = BILLING_ACCENT[plan.id] || "var(--muted)";
            return (
              <div key={plan.id} className="card" style={{
                position: "relative",
                border: "1px solid " + (isCurrent ? accent : "var(--border)"),
              }}>
                {isCurrent && (
                  <div style={{
                    position: "absolute", top: 12, right: 12,
                    fontSize: 11, fontFamily: "var(--ff-mono)", color: accent,
                    background: "var(--panel-2)", padding: "2px 8px", borderRadius: 5,
                  }}>CURRENT</div>
                )}
                <div className="card-body" style={{
                  display: "flex", flexDirection: "column", gap: 14, minHeight: 318,
                }}>
                  <div>
                    <div style={{ fontSize: 15, fontWeight: 600, color: accent }}>{plan.name}</div>
                    <div style={{ marginTop: 8 }}>
                      <span style={{ fontSize: 30, fontWeight: 600, letterSpacing: "-0.02em" }}>
                        {"$" + plan.price_usd}
                      </span>
                      <span className="mono text-xs muted"> / {plan.is_paid ? "month" : "forever"}</span>
                    </div>
                  </div>
                  <div style={{ display: "flex", flexDirection: "column", gap: 9, flex: 1 }}>
                    {billingFeatures(plan).map((f, i) => (
                      <div key={i} className="row gap-6" style={{ fontSize: 13, color: "var(--text-dim)" }}>
                        <Icon.Check style={{ width: 13, height: 13, color: accent, flex: "0 0 13px" }} />
                        <span>{f}</span>
                      </div>
                    ))}
                  </div>
                  {billingPlanButton(plan, isCurrent, hasActiveSub, isCanceling, busy, askUpgrade, askCancel)}
                </div>
              </div>
            );
          })}
        </div>

        <div style={{
          marginTop: 18, padding: 14, border: "1px dashed var(--border)", borderRadius: 10,
          fontSize: 12.5, color: "var(--text-dim)", display: "flex", gap: 10, alignItems: "center",
        }}>
          <Icon.Shield style={{ width: 15, height: 15, color: "var(--cyan)", flex: "0 0 15px" }} />
          <span>
            Payments are processed securely off-site. Market-Options never sees or stores
            your card details, and you can cancel your subscription at any time.
          </span>
        </div>
      </div>
    </>
  );
}

Object.assign(window, { BillingPage });
