"use client";

import {
  useCallback,
  useEffect,
  useRef,
  useState,
  type ClipboardEvent,
  type KeyboardEvent,
} from "react";

type Step = "loading" | "details" | "otp" | "paying" | "done" | "error";

type RazorpaySuccess = {
  razorpay_order_id: string;
  razorpay_payment_id: string;
  razorpay_signature: string;
};

type RazorpayFailure = {
  error?: {
    code?: string;
    description?: string;
    source?: string;
    step?: string;
    reason?: string;
    metadata?: { order_id?: string; payment_id?: string };
  };
};

declare global {
  interface Window {
    Razorpay?: new (options: Record<string, unknown>) => {
      open: () => void;
      on: (event: string, handler: (resp: RazorpayFailure) => void) => void;
    };
  }
}

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

function formatInr(n: number) {
  return new Intl.NumberFormat("en-IN", {
    style: "currency",
    currency: "INR",
    maximumFractionDigits: 2,
  }).format(n);
}

export default function DirectPayClient({ orderId }: { orderId: string }) {
  const [step, setStep] = useState<Step>("loading");
  const [maskedPhone, setMaskedPhone] = useState("");
  const [due, setDue] = useState(0);
  const [total, setTotal] = useState(0);
  const [otp, setOtp] = useState(["", "", "", "", ""]);
  const [msg, setMsg] = useState("");
  const [msgType, setMsgType] = useState<"error" | "success">("error");
  const [busy, setBusy] = useState(false);
  const [resendIn, setResendIn] = useState(0);
  const [popupOpen, setPopupOpen] = useState(false);
  const inputsRef = useRef<Array<HTMLInputElement | null>>([]);
  const startedRef = useRef(false);
  const payingRef = useRef(false);
  const tokenRef = useRef("");
  const dueRef = useRef(0);

  const showMsg = useCallback((text: string, type: "error" | "success" = "error") => {
    setMsg(text);
    setMsgType(type);
  }, []);

  const lookupOrder = useCallback(async () => {
    setStep("loading");
    try {
      const res = await fetch("/api/payments/direct/lookup", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ orderNo: orderId }),
      });
      const data = await res.json();
      if (!res.ok || !data.success) {
        setStep("error");
        showMsg(data.error || "Could not find this order.");
        return;
      }
      setMaskedPhone(data.maskedPhone || "");
      const dueAmount = typeof data.due === "number" ? data.due : parseFloat(data.due) || 0;
      const totalAmount = typeof data.total === "number" ? data.total : parseFloat(data.total) || 0;
      setDue(dueAmount);
      dueRef.current = dueAmount;
      setTotal(totalAmount);
      setStep("details");
    } catch {
      setStep("error");
      showMsg("Network error. Please try again.");
    }
  }, [orderId, showMsg]);

  const startOtp = useCallback(
    async (isResend = false) => {
      setBusy(true);
      if (!isResend) {
        setPopupOpen(true);
        setStep("loading");
      }
      try {
        const res = await fetch("/api/payments/direct/start", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ orderNo: orderId }),
        });
        const data = await res.json();
        if (!res.ok || !data.success) {
          setPopupOpen(false);
          setStep("error");
          showMsg(data.error || "Could not start payment for this order.");
          return;
        }
        setMaskedPhone(data.maskedPhone || "");
        const amount = typeof data.due === "number" ? data.due : parseFloat(data.due) || 0;
        setDue(amount);
        dueRef.current = amount;
        setPopupOpen(true);
        setStep("otp");
        setResendIn(30);
        showMsg(
          isResend ? "OTP resent to your registered mobile." : "OTP sent to your registered mobile.",
          "success"
        );
        setTimeout(() => inputsRef.current[0]?.focus(), 80);
      } catch {
        setPopupOpen(false);
        setStep("error");
        showMsg("Network error. Please try again.");
      } finally {
        setBusy(false);
      }
    },
    [orderId, showMsg]
  );

  async function postPaymentResponse(
    token: string,
    status: "success" | "failed" | "cancelled",
    extra: Record<string, unknown> = {}
  ) {
    return fetch("/api/payments/response", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${token}`,
      },
      body: JSON.stringify({
        status,
        orderNo: orderId,
        amount: dueRef.current,
        ...extra,
      }),
    }).then(async (r) => {
      const data = await r.json().catch(() => ({}));
      return { ok: r.ok, data };
    });
  }

  const openCheckout = useCallback(
    async (token: string) => {
      if (payingRef.current) return;
      payingRef.current = true;
      tokenRef.current = token;
      setPopupOpen(true);
      setStep("paying");
      setBusy(true);
      showMsg("");

      let cancelPosted = false;
      let rzpOrderId = "";

      try {
        await loadRazorpay();
        const res = await fetch("/api/payments/create-order", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
            Authorization: `Bearer ${token}`,
          },
          body: JSON.stringify({ orderNo: orderId }),
        });
        const data = await res.json();
        if (!res.ok || !data.orderId) {
          throw new Error(data.error || "Could not start payment");
        }

        if (typeof data.amount === "number") {
          const amount = data.amount / 100;
          setDue(amount);
          dueRef.current = amount;
        }
        rzpOrderId = data.orderId;
        if (!window.Razorpay) throw new Error("Razorpay unavailable");

        const rzp = new window.Razorpay({
          key: data.keyId,
          amount: data.amount,
          currency: data.currency || "INR",
          name: "The Swiss Laundry",
          description: `Payment for order ${orderId}`,
          order_id: data.orderId,
          prefill: data.prefill || {},
          notes: { orderNo: orderId },
          theme: { color: "#C9A84C" },
          modal: {
            ondismiss: () => {
              if (cancelPosted) {
                payingRef.current = false;
                setBusy(false);
                return;
              }
              cancelPosted = true;
              void postPaymentResponse(token, "cancelled", {
                razorpay_order_id: rzpOrderId,
              }).finally(() => {
                payingRef.current = false;
                setBusy(false);
                setPopupOpen(false);
                setStep("error");
                showMsg("Payment cancelled. You can try again.");
              });
            },
          },
          handler: (response: RazorpaySuccess) => {
            cancelPosted = true;
            void postPaymentResponse(token, "success", {
              razorpay_order_id: response.razorpay_order_id,
              razorpay_payment_id: response.razorpay_payment_id,
              razorpay_signature: response.razorpay_signature,
            }).then((v) => {
              if (v.ok && v.data?.success) {
                setPopupOpen(false);
                setStep("done");
                showMsg(v.data.message || "Payment successful.", "success");
                setTimeout(() => {
                  window.location.href = "/track-order";
                }, 1200);
              } else {
                payingRef.current = false;
                setBusy(false);
                setPopupOpen(false);
                setStep("error");
                showMsg(
                  v.data?.error ||
                    v.data?.message ||
                    `Payment received but could not verify. WhatsApp us with ${response.razorpay_payment_id}`
                );
              }
            });
          },
        });

        rzp.on("payment.failed", (resp) => {
          cancelPosted = true;
          const err = resp?.error || {};
          void postPaymentResponse(token, "failed", {
            razorpay_order_id: err.metadata?.order_id || rzpOrderId,
            razorpay_payment_id: err.metadata?.payment_id || "",
            error: {
              code: err.code || "",
              description: err.description || "",
              source: err.source || "",
              step: err.step || "",
              reason: err.reason || "",
            },
          }).finally(() => {
            payingRef.current = false;
            setBusy(false);
            setPopupOpen(false);
            setStep("error");
            showMsg(err.description || "Payment failed. Please try again.");
          });
        });

        rzp.open();
        setBusy(false);
      } catch (err) {
        payingRef.current = false;
        setBusy(false);
        setPopupOpen(false);
        setStep("error");
        showMsg(err instanceof Error ? err.message : "Could not open Razorpay.");
      }
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [orderId, showMsg]
  );

  useEffect(() => {
    if (startedRef.current) return;
    startedRef.current = true;

    const existing = sessionStorage.getItem("tsl_token");
    if (existing) {
      setPopupOpen(true);
      void openCheckout(existing);
      return;
    }
    void lookupOrder();
  }, [openCheckout, lookupOrder]);

  useEffect(() => {
    if (resendIn <= 0) return;
    const t = setInterval(() => setResendIn((s) => (s <= 1 ? 0 : s - 1)), 1000);
    return () => clearInterval(t);
  }, [resendIn]);

  async function verifyOtp(code: string) {
    if (busy || code.length !== 5) return;
    setBusy(true);
    showMsg("");
    try {
      const res = await fetch("/api/payments/direct/verify", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ orderNo: orderId, otp: code }),
      });
      const data = await res.json();
      if (!res.ok || !data.success || !data.token) {
        showMsg(data.error || "Incorrect OTP. Please try again.");
        setBusy(false);
        return;
      }
      sessionStorage.setItem("tsl_token", data.token);
      sessionStorage.setItem("tsl_verified", "1");
      try {
        window.dispatchEvent(new Event("tsl-auth-change"));
      } catch {
        /* ignore */
      }
      showMsg("Verified — opening payment…", "success");
      await openCheckout(data.token);
    } catch {
      showMsg("Could not verify right now. Please try again.");
      setBusy(false);
    }
  }

  function onOtpChange(index: number, value: string) {
    const digit = value.replace(/\D/g, "").slice(-1);
    const next = [...otp];
    next[index] = digit;
    setOtp(next);
    if (digit && index < 4) inputsRef.current[index + 1]?.focus();
    const joined = next.join("");
    if (joined.length === 5) void verifyOtp(joined);
  }

  function onOtpKeyDown(index: number, e: KeyboardEvent<HTMLInputElement>) {
    if (e.key === "Backspace" && !otp[index] && index > 0) {
      inputsRef.current[index - 1]?.focus();
    }
  }

  function onOtpPaste(e: ClipboardEvent) {
    e.preventDefault();
    const pasted = e.clipboardData.getData("text").replace(/\D/g, "").slice(0, 5);
    if (!pasted) return;
    const next = ["", "", "", "", ""];
    pasted.split("").forEach((ch, i) => {
      next[i] = ch;
    });
    setOtp(next);
    if (pasted.length === 5) void verifyOtp(pasted);
    else inputsRef.current[Math.min(pasted.length, 4)]?.focus();
  }

  function retry() {
    const token = tokenRef.current || sessionStorage.getItem("tsl_token") || "";
    if (token) {
      payingRef.current = false;
      setPopupOpen(true);
      void openCheckout(token);
      return;
    }
    setOtp(["", "", "", "", ""]);
    void lookupOrder();
  }

  return (
    <main className="dp-page">
      <div className="dp-bg" aria-hidden="true" />
      <section className="dp-shell" aria-label="Direct payment">
        <p className="dp-brand">The Swiss Laundry</p>
        <h1 className="dp-title">Pay for your order</h1>
        <p className="dp-order">
          Order <span>{orderId}</span>
          {due > 0 ? (
            <>
              {" "}
              · Due <strong>{formatInr(due)}</strong>
            </>
          ) : null}
        </p>

        {step === "loading" && !popupOpen && <div className="dp-spinner" aria-hidden="true" />}

        {step === "details" && (
          <div className="dp-details">
            <dl className="dp-details-list">
              <div>
                <dt>Order number</dt>
                <dd>{orderId}</dd>
              </div>
              {total > 0 && (
                <div>
                  <dt>Total amount</dt>
                  <dd>{formatInr(total)}</dd>
                </div>
              )}
              <div>
                <dt>Total due</dt>
                <dd>{formatInr(due)}</dd>
              </div>
            </dl>
            {msg ? (
              <p className={`dp-msg ${msgType}`} role="alert">
                {msg}
              </p>
            ) : null}
            <button
              type="button"
              className="dp-btn"
              disabled={busy}
              onClick={() => void startOtp(false)}
            >
              {busy ? "Sending OTP…" : "Send OTP to Pay"}
            </button>
          </div>
        )}

        {popupOpen && (step === "loading" || step === "otp" || step === "paying") && (
          <div className="dp-modal" role="dialog" aria-modal="true" aria-labelledby="dp-modal-title">
            <div className="dp-modal-card">
              <h2 id="dp-modal-title" className="dp-modal-title">
                {step === "paying"
                  ? "Opening Razorpay…"
                  : step === "loading"
                    ? "Sending OTP…"
                    : "Verify with OTP"}
              </h2>
              <p className="dp-modal-sub">
                {step === "paying"
                  ? "Complete payment in the Razorpay window."
                  : step === "loading"
                    ? "Sending a one-time password to the mobile number on this order."
                    : maskedPhone
                      ? `OTP sent to +91 ${maskedPhone}`
                      : "Enter the OTP sent to your registered mobile."}
              </p>

              {msg ? (
                <p className={`dp-msg ${msgType}`} role="alert">
                  {msg}
                </p>
              ) : null}

              {step === "otp" && (
                <>
                  <div className="dp-otp-row" role="group" aria-label="Enter 5-digit OTP">
                    {otp.map((d, i) => (
                      <input
                        key={i}
                        ref={(el) => {
                          inputsRef.current[i] = el;
                        }}
                        className={`dp-otp ${d ? "filled" : ""}`}
                        type="text"
                        inputMode="numeric"
                        maxLength={1}
                        value={d}
                        disabled={busy}
                        aria-label={`OTP digit ${i + 1}`}
                        autoComplete={i === 0 ? "one-time-code" : "off"}
                        onChange={(e) => onOtpChange(i, e.target.value)}
                        onKeyDown={(e) => onOtpKeyDown(i, e)}
                        onPaste={onOtpPaste}
                      />
                    ))}
                  </div>
                  <button
                    type="button"
                    className="dp-btn"
                    disabled={busy || otp.join("").length !== 5}
                    onClick={() => void verifyOtp(otp.join(""))}
                  >
                    {busy ? "Verifying…" : "Verify & Pay"}
                  </button>
                  <div className="dp-resend">
                    {resendIn > 0 ? (
                      <span>
                        Resend OTP in <em>{resendIn}s</em>
                      </span>
                    ) : (
                      <button
                        type="button"
                        className="dp-link"
                        disabled={busy}
                        onClick={() => void startOtp(true)}
                      >
                        Resend OTP
                      </button>
                    )}
                  </div>
                </>
              )}

              {(step === "loading" || step === "paying") && (
                <div className="dp-spinner" aria-hidden="true" />
              )}
            </div>
          </div>
        )}

        {step === "done" && (
          <div className="dp-result ok">
            <p>Payment successful. Redirecting to track order…</p>
          </div>
        )}

        {step === "error" && (
          <div className="dp-result err">
            <p>{msg || "Something went wrong."}</p>
            <button type="button" className="dp-btn" onClick={retry}>
              Try again
            </button>
            <a className="dp-link" href="/track-order">
              Go to Track Order
            </a>
          </div>
        )}
      </section>

      <style jsx>{`
        .dp-page {
          min-height: 100svh;
          position: relative;
          display: flex;
          align-items: center;
          justify-content: center;
          padding: 6rem 1.25rem 4rem;
          background: var(--dark2, #1a1918);
          color: #fff;
        }
        .dp-bg {
          position: absolute;
          inset: 0;
          background:
            radial-gradient(ellipse 70% 50% at 70% 20%, rgba(201, 168, 76, 0.08), transparent 60%),
            radial-gradient(ellipse 50% 40% at 10% 80%, rgba(192, 65, 90, 0.08), transparent 55%);
          pointer-events: none;
        }
        .dp-shell {
          position: relative;
          z-index: 1;
          width: min(440px, 100%);
          text-align: center;
        }
        .dp-brand {
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 10px;
          letter-spacing: 0.32em;
          text-transform: uppercase;
          color: var(--gold, #c9a84c);
          margin-bottom: 0.8rem;
        }
        .dp-title {
          font-family: var(--serif, "Cormorant Garamond", Georgia, serif);
          font-style: italic;
          font-weight: 300;
          font-size: clamp(32px, 6vw, 46px);
          letter-spacing: -0.02em;
          line-height: 1.1;
          margin-bottom: 0.7rem;
        }
        .dp-order {
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 13px;
          font-weight: 300;
          color: rgba(255, 255, 255, 0.45);
          margin-bottom: 2rem;
        }
        .dp-order span,
        .dp-order strong {
          color: rgba(255, 255, 255, 0.85);
          font-weight: 400;
        }
        .dp-modal {
          position: fixed;
          inset: 0;
          z-index: 100100;
          display: flex;
          align-items: center;
          justify-content: center;
          padding: 1.25rem;
          background: rgba(12, 11, 10, 0.72);
          backdrop-filter: blur(10px);
        }
        .dp-modal-card {
          width: min(400px, 100%);
          background: #201e1d;
          border: 0.5px solid rgba(255, 255, 255, 0.1);
          border-radius: 4px;
          padding: 2rem 1.6rem 1.6rem;
          position: relative;
          overflow: hidden;
          animation: dpIn 0.35s cubic-bezier(0.16, 1, 0.3, 1);
        }
        .dp-modal-card::before {
          content: "";
          position: absolute;
          top: 0;
          left: 0;
          right: 0;
          height: 2px;
          background: linear-gradient(90deg, transparent, var(--gold, #c9a84c), transparent);
        }
        @keyframes dpIn {
          from {
            opacity: 0;
            transform: translateY(12px) scale(0.98);
          }
          to {
            opacity: 1;
            transform: none;
          }
        }
        .dp-modal-title {
          font-family: var(--serif, "Cormorant Garamond", Georgia, serif);
          font-style: italic;
          font-weight: 300;
          font-size: 24px;
          margin-bottom: 0.5rem;
        }
        .dp-modal-sub {
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 12px;
          font-weight: 300;
          color: rgba(255, 255, 255, 0.4);
          line-height: 1.7;
          margin-bottom: 1.4rem;
        }
        .dp-msg {
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 12px;
          font-weight: 300;
          padding: 0.65rem 0.85rem;
          border-radius: 2px;
          margin-bottom: 1rem;
          text-align: left;
        }
        .dp-msg.error {
          background: rgba(192, 65, 90, 0.15);
          color: #ff9999;
          border: 0.5px solid rgba(192, 65, 90, 0.3);
        }
        .dp-msg.success {
          background: rgba(37, 211, 102, 0.1);
          color: #90ee90;
          border: 0.5px solid rgba(37, 211, 102, 0.2);
        }
        .dp-otp-row {
          display: flex;
          gap: 0.55rem;
          justify-content: center;
          margin-bottom: 1.2rem;
        }
        .dp-otp {
          width: 48px;
          height: 56px;
          text-align: center;
          background: rgba(255, 255, 255, 0.05);
          border: 0.5px solid rgba(255, 255, 255, 0.12);
          border-radius: 2px;
          color: #fff;
          font-family: var(--serif, "Cormorant Garamond", Georgia, serif);
          font-style: italic;
          font-size: 26px;
          font-weight: 300;
          outline: none;
          caret-color: var(--gold, #c9a84c);
        }
        .dp-otp:focus {
          border-color: rgba(201, 168, 76, 0.55);
          background: rgba(201, 168, 76, 0.05);
        }
        .dp-otp.filled {
          border-color: rgba(255, 255, 255, 0.22);
        }
        .dp-btn {
          width: 100%;
          padding: 0.95rem;
          background: var(--gold, #c9a84c);
          color: #0c0b0a;
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 10px;
          font-weight: 500;
          letter-spacing: 0.18em;
          text-transform: uppercase;
          border: none;
          border-radius: 2px;
          cursor: pointer;
        }
        .dp-btn:hover:not(:disabled) {
          background: var(--gold-l, #e2c97e);
        }
        .dp-btn:disabled {
          opacity: 0.45;
          cursor: not-allowed;
        }
        .dp-resend {
          margin-top: 0.9rem;
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 11px;
          color: rgba(255, 255, 255, 0.3);
        }
        .dp-resend em {
          color: var(--gold, #c9a84c);
          font-style: normal;
        }
        .dp-link {
          display: inline-block;
          margin-top: 0.85rem;
          background: none;
          border: none;
          color: rgba(255, 255, 255, 0.45);
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 11px;
          letter-spacing: 0.08em;
          text-decoration: underline;
          cursor: pointer;
        }
        .dp-link:hover {
          color: rgba(255, 255, 255, 0.75);
        }
        .dp-spinner {
          width: 28px;
          height: 28px;
          margin: 1.2rem auto 0.4rem;
          border: 2px solid rgba(255, 255, 255, 0.15);
          border-top-color: var(--gold, #c9a84c);
          border-radius: 50%;
          animation: spin 0.7s linear infinite;
        }
        @keyframes spin {
          to {
            transform: rotate(360deg);
          }
        }
        .dp-details {
          padding: 1.6rem;
          border: 0.5px solid rgba(255, 255, 255, 0.1);
          background: rgba(255, 255, 255, 0.04);
          border-radius: 4px;
          text-align: left;
        }
        .dp-details-list {
          margin: 0 0 1.2rem;
        }
        .dp-details-list > div {
          display: flex;
          justify-content: space-between;
          align-items: baseline;
          padding: 0.55rem 0;
          border-bottom: 0.5px solid rgba(255, 255, 255, 0.08);
        }
        .dp-details-list > div:last-child {
          border-bottom: none;
        }
        .dp-details-list dt {
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 11px;
          font-weight: 300;
          letter-spacing: 0.04em;
          color: rgba(255, 255, 255, 0.45);
        }
        .dp-details-list dd {
          margin: 0;
          font-family: var(--serif, "Cormorant Garamond", Georgia, serif);
          font-size: 18px;
          font-weight: 400;
          color: #fff;
        }
        .dp-result {
          padding: 1.6rem;
          border: 0.5px solid rgba(255, 255, 255, 0.1);
          background: rgba(255, 255, 255, 0.04);
          border-radius: 4px;
        }
        .dp-result p {
          font-family: var(--sans, "Jost", sans-serif);
          font-size: 13px;
          font-weight: 300;
          line-height: 1.7;
          margin-bottom: 1rem;
          color: rgba(255, 255, 255, 0.7);
        }
        .dp-result.ok p {
          color: #90ee90;
        }
        @media (max-width: 480px) {
          .dp-otp {
            width: 42px;
            height: 50px;
            font-size: 22px;
          }
        }
      `}</style>
    </main>
  );
}
