"use client";

import { useEffect, useRef, useState } from "react";
import { FlaskConical } from "lucide-react";
import { Button, Dialog } from "@/components/ui/kit";
import { api } from "@/lib/api";
import { formatPaise } from "@/lib/format";
import type { Checkout, Payment } from "@/lib/types";

type RazorpayResponse = { razorpay_order_id: string; razorpay_payment_id: string; razorpay_signature: string };
type RazorpayInstance = { open: () => void; on: (event: string, cb: (r: { error?: { description?: string } }) => void) => void };
declare global {
  interface Window {
    Razorpay?: new (options: Record<string, unknown>) => RazorpayInstance;
  }
}

const SCRIPT = "https://checkout.razorpay.com/v1/checkout.js";
function loadRazorpay(): Promise<void> {
  if (window.Razorpay) return Promise.resolve();
  return new Promise((resolve, reject) => {
    const s = document.createElement("script");
    s.src = SCRIPT;
    s.async = true;
    s.onload = () => resolve();
    s.onerror = () => reject(new Error("Could not load Razorpay Checkout. Check your connection and try again."));
    document.body.appendChild(s);
  });
}

/**
 * Runs a checkout created by the API. Real mode opens Razorpay Checkout; the result is always confirmed by
 * our server (signature + Razorpay lookup) before anything is credited. Simulation mode (no Razorpay keys
 * in development) shows a test dialog that goes through the same server verification.
 */
export function CheckoutRunner({ checkout, onDone }: { checkout: Checkout; onDone: (p: Payment | null, error?: string) => void }) {
  const [busy, setBusy] = useState<"success" | "failure" | null>(null);
  const opened = useRef(false);

  async function verify(r: RazorpayResponse) {
    try {
      const res = await api.post<{ data: Payment }>("/billing/payments/verify", r);
      onDone(res.data);
    } catch (e) {
      onDone(null, (e as Error).message);
    }
  }

  useEffect(() => {
    if (checkout.simulation || opened.current) return;
    opened.current = true;
    loadRazorpay()
      .then(() => {
        const rzp = new window.Razorpay!({
          key: checkout.key_id,
          amount: checkout.total_paise,
          currency: checkout.currency,
          order_id: checkout.order_id,
          name: checkout.name,
          description: checkout.description,
          prefill: checkout.prefill,
          theme: { color: "#0e6b5c" },
          handler: (r: RazorpayResponse) => verify(r),
          modal: {
            ondismiss: () => {
              api.post(`/billing/payments/${checkout.payment_id}/abandon`, { reason: "Checkout closed before paying" }).catch(() => undefined);
              onDone(null);
            },
          },
        });
        rzp.on("payment.failed", (r) => {
          // Checkout lets the customer retry; we only record the reason for now.
          console.warn("Payment attempt failed:", r.error?.description);
        });
        rzp.open();
      })
      .catch((e: Error) => onDone(null, e.message));
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  async function simulate(outcome: "success" | "failure") {
    setBusy(outcome);
    try {
      const s = await api.post<{ data: RazorpayResponse }>(`/billing/payments/${checkout.payment_id}/simulate`, { outcome });
      await verify(s.data);
    } catch (e) {
      onDone(null, (e as Error).message);
    } finally {
      setBusy(null);
    }
  }

  if (!checkout.simulation) return null;
  return (
    <Dialog
      open
      onClose={() => {
        api.post(`/billing/payments/${checkout.payment_id}/abandon`).catch(() => undefined);
        onDone(null);
      }}
      title="Test payment"
      description="Razorpay isn't connected on this server, so this simulates the payment. It still goes through the same server-side verification."
      footer={
        <>
          <Button onClick={() => simulate("failure")} loading={busy === "failure"} disabled={busy !== null}>
            Simulate a decline
          </Button>
          <Button variant="primary" onClick={() => simulate("success")} loading={busy === "success"} disabled={busy !== null}>
            Pay {formatPaise(checkout.total_paise)}
          </Button>
        </>
      }
    >
      <div className="space-y-3 text-sm">
        <p className="flex items-center gap-2 rounded-md bg-amber-soft px-3 py-2 text-amber">
          <FlaskConical className="size-4 shrink-0" /> No real money moves in test mode.
        </p>
        <dl className="grid grid-cols-[1fr_auto] gap-y-1.5">
          <dt className="text-muted">{checkout.description}</dt>
          <dd className="tabular text-right">{formatPaise(checkout.amount_paise)}</dd>
          <dt className="text-muted">GST</dt>
          <dd className="tabular text-right">{formatPaise(checkout.tax_paise)}</dd>
          <dt className="border-t border-line pt-1.5 font-semibold">Total</dt>
          <dd className="tabular border-t border-line pt-1.5 text-right font-semibold">{formatPaise(checkout.total_paise)}</dd>
        </dl>
      </div>
    </Dialog>
  );
}
