"use client";

import { useMemo, useState } from "react";
import { useRouter } from "next/navigation";
import Image from "next/image";
import Script from "next/script";
import Link from "next/link";
import { useCart } from "@/lib/cart-context";
import { useToast } from "@/lib/toast-context";
import { formatPrice } from "@/lib/format";
import { siteConfig } from "@/lib/siteConfig";
import { EmptyState } from "@/components/EmptyState";

declare global {
  interface Window {
    PaystackPop?: new () => {
      newTransaction: (opts: Record<string, unknown>) => void;
    };
  }
}

type Step = "form" | "paying" | "verifying";

export default function CheckoutPage() {
  const { lines, catalog, subtotal, clear } = useCart();
  const { show } = useToast();
  const router = useRouter();

  const [name, setName] = useState("");
  const [phone, setPhone] = useState("");
  const [email, setEmail] = useState("");
  const [city, setCity] = useState("");
  const [address, setAddress] = useState("");
  const [instructions, setInstructions] = useState("");
  const [promoInput, setPromoInput] = useState("");
  const [appliedPromo, setAppliedPromo] = useState<string | undefined>();
  const [discount, setDiscount] = useState(0);
  const [promoError, setPromoError] = useState("");
  const [checkingPromo, setCheckingPromo] = useState(false);
  const [submitError, setSubmitError] = useState("");
  const [step, setStep] = useState<Step>("form");

  const resolvedLines = lines
    .map((l) => ({ line: l, product: catalog.find((p) => p.id === l.productId) }))
    .filter((x) => x.product);

  const total = Math.max(0, subtotal - discount) + siteConfig.deliveryFee;

  async function applyPromo() {
    if (!promoInput.trim()) return;
    setCheckingPromo(true);
    setPromoError("");
    try {
      const res = await fetch("/api/promo", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ code: promoInput, lines }),
      });
      const data = await res.json();
      if (!res.ok || !data.valid) {
        setPromoError(data.message || "That promo code isn't valid.");
        setAppliedPromo(undefined);
        setDiscount(0);
      } else {
        setAppliedPromo(data.code);
        setDiscount(data.discount);
      }
    } catch {
      setPromoError("Couldn't check that code. Try again.");
    } finally {
      setCheckingPromo(false);
    }
  }

  const canSubmit =
    resolvedLines.length > 0 &&
    name.trim() &&
    phone.trim() &&
    email.trim() &&
    city.trim() &&
    address.trim();

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    if (!canSubmit) return;
    setSubmitError("");
    setStep("paying");

    try {
      const res = await fetch("/api/checkout", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          lines,
          customer: { name, phone, email, city, address, instructions },
          promoCode: appliedPromo,
        }),
      });
      const data = await res.json();
      if (!res.ok) {
        setSubmitError(data.message || "Something went wrong. Please try again.");
        setStep("form");
        return;
      }

      const { orderId, total: orderTotal } = data;

      if (!window.PaystackPop) {
        setSubmitError("Payment could not load. Please refresh and try again.");
        setStep("form");
        return;
      }

      const publicKey = process.env.NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY;
      if (!publicKey) {
        setSubmitError(
          "Payments aren't configured yet. Add NEXT_PUBLIC_PAYSTACK_PUBLIC_KEY."
        );
        setStep("form");
        return;
      }

      const paystack = new window.PaystackPop();
      paystack.newTransaction({
        key: publicKey,
        email,
        amount: Math.round(orderTotal * 100),
        currency: siteConfig.currency,
        reference: orderId,
        metadata: {
          custom_fields: [
            { display_name: "Order ID", variable_name: "order_id", value: orderId },
          ],
        },
        onSuccess: async (transaction: { reference: string }) => {
          setStep("verifying");
          try {
            const verifyRes = await fetch("/api/paystack/verify", {
              method: "POST",
              headers: { "Content-Type": "application/json" },
              body: JSON.stringify({ reference: transaction.reference }),
            });
            const verifyData = await verifyRes.json();
            if (verifyRes.ok && verifyData.paid) {
              clear();
              router.push(`/order/${orderId}`);
              return;
            }
            show(
              "Payment received. We're confirming it now. Check your order status shortly.",
              "info"
            );
            clear();
            router.push(`/order/${orderId}`);
          } catch {
            show("Payment received. Check your order status for confirmation.", "info");
            clear();
            router.push(`/order/${orderId}`);
          }
        },
        onCancel: () => {
          setStep("form");
          show("Payment was not completed.", "error");
        },
        onError: (err: { message: string }) => {
          setStep("form");
          setSubmitError(err?.message || "Payment failed. Please try again.");
        },
      });
    } catch {
      setSubmitError("Something went wrong. Please try again.");
      setStep("form");
    }
  }

  if (resolvedLines.length === 0) {
    return (
      <div className="mx-auto max-w-2xl px-4 py-16 sm:px-6">
        <EmptyState
          title="Your cart is empty"
          description="Add a product before checking out."
          action={
            <Link
              href="/"
              className="inline-block rounded-lg bg-brand-ink px-4 py-2 text-sm font-semibold text-white hover:bg-black"
            >
              Continue shopping
            </Link>
          }
        />
      </div>
    );
  }

  return (
    <div className="mx-auto max-w-6xl px-4 py-8 sm:px-6 lg:px-8">
      <Script src="https://js.paystack.co/v2/inline.js" strategy="afterInteractive" />
      <h1 className="font-display text-2xl font-bold text-brand-ink sm:text-3xl">Checkout</h1>
      <p className="mt-1 text-sm text-black/55">
        Guest checkout, no account needed.
      </p>

      <div className="mt-8 grid gap-10 lg:grid-cols-[1fr_380px]">
        <form onSubmit={handleSubmit} className="flex flex-col gap-6">
          <fieldset className="flex flex-col gap-4">
            <legend className="mb-1 font-display text-lg font-semibold text-brand-ink">
              Your details
            </legend>
            <div className="grid gap-4 sm:grid-cols-2">
              <Field label="Full name" value={name} onChange={setName} required />
              <Field label="Phone number" value={phone} onChange={setPhone} required type="tel" />
            </div>
            <Field label="Email address" value={email} onChange={setEmail} required type="email" />
          </fieldset>

          <fieldset className="flex flex-col gap-4">
            <legend className="mb-1 font-display text-lg font-semibold text-brand-ink">
              Delivery
            </legend>
            <Field
              label="Area in Asaba"
              value={city}
              onChange={setCity}
              required
              placeholder="e.g. Okpanam Road, Cable Point"
            />
            <Field
              label="Delivery address"
              value={address}
              onChange={setAddress}
              required
              textarea
              placeholder="Street, house number, landmark"
            />
            <Field
              label="Delivery instructions (optional)"
              value={instructions}
              onChange={setInstructions}
              textarea
              placeholder="e.g. call on arrival, gate code, preferred time"
            />
          </fieldset>

          {submitError && (
            <p className="rounded-lg bg-red-50 px-3.5 py-2.5 text-sm text-danger">{submitError}</p>
          )}

          <button
            type="submit"
            disabled={!canSubmit || step !== "form"}
            className="rounded-lg bg-brand-orange py-3.5 text-sm font-semibold text-white transition hover:bg-brand-orange-dark disabled:cursor-not-allowed disabled:bg-black/15 disabled:text-black/40"
          >
            {step === "paying"
              ? "Opening payment..."
              : step === "verifying"
              ? "Confirming payment..."
              : `Pay ${formatPrice(total)} with Paystack`}
          </button>
          <p className="text-center text-xs text-black/40">
            Secure card, bank transfer and USSD payments via Paystack.
          </p>
        </form>

        <aside className="h-fit rounded-2xl border border-black/[0.06] bg-black/[0.015] p-5">
          <h2 className="font-display text-base font-semibold text-brand-ink">Order summary</h2>
          <ul className="mt-4 flex flex-col gap-3">
            {resolvedLines.map(({ line, product }) => (
              <li key={line.productId} className="flex gap-3">
                <div className="relative h-14 w-14 shrink-0 overflow-hidden rounded-lg bg-brand-cream">
                  <Image
                    src={product!.images[0] ?? "/images/products/placeholder.webp"}
                    alt={product!.name}
                    fill
                    sizes="56px"
                    className="object-cover"
                  />
                </div>
                <div className="min-w-0 flex-1">
                  <p className="line-clamp-1 text-sm font-medium text-brand-ink">
                    {product!.name}
                  </p>
                  <p className="text-xs text-black/45">Qty {line.quantity}</p>
                </div>
                <span className="shrink-0 text-sm font-medium text-brand-ink">
                  {formatPrice(product!.price * line.quantity)}
                </span>
              </li>
            ))}
          </ul>

          <div className="mt-5 border-t border-black/[0.06] pt-4">
            <div className="flex gap-2">
              <input
                type="text"
                value={promoInput}
                onChange={(e) => setPromoInput(e.target.value)}
                placeholder="Promo code"
                className="flex-1 rounded-lg border border-black/10 px-3 py-2 text-sm focus:border-brand-orange focus:outline-none"
              />
              <button
                type="button"
                onClick={applyPromo}
                disabled={checkingPromo}
                className="rounded-lg border border-black/10 px-3.5 py-2 text-sm font-medium text-brand-ink hover:bg-black/5"
              >
                Apply
              </button>
            </div>
            {promoError && <p className="mt-1.5 text-xs text-danger">{promoError}</p>}
            {appliedPromo && (
              <p className="mt-1.5 text-xs text-success">
                Code &ldquo;{appliedPromo}&rdquo; applied.
              </p>
            )}
          </div>

          <div className="mt-4 flex flex-col gap-2 border-t border-black/[0.06] pt-4 text-sm">
            <Row label="Subtotal" value={formatPrice(subtotal)} />
            {discount > 0 && <Row label="Discount" value={`-${formatPrice(discount)}`} />}
            <Row label="Delivery" value={formatPrice(siteConfig.deliveryFee)} />
            <div className="mt-1 flex items-center justify-between border-t border-black/[0.06] pt-3 text-base font-semibold text-brand-ink">
              <span>Total</span>
              <span>{formatPrice(total)}</span>
            </div>
          </div>
        </aside>
      </div>
    </div>
  );
}

function Row({ label, value }: { label: string; value: string }) {
  return (
    <div className="flex items-center justify-between text-black/60">
      <span>{label}</span>
      <span className="text-brand-ink">{value}</span>
    </div>
  );
}

function Field({
  label,
  value,
  onChange,
  required,
  type = "text",
  textarea,
  placeholder,
}: {
  label: string;
  value: string;
  onChange: (v: string) => void;
  required?: boolean;
  type?: string;
  textarea?: boolean;
  placeholder?: string;
}) {
  const id = useMemo(
    () => `field-${label.toLowerCase().replace(/[^a-z0-9]+/g, "-")}`,
    [label]
  );
  return (
    <div className="flex flex-col gap-1.5">
      <label htmlFor={id} className="text-sm font-medium text-brand-ink">
        {label} {required && <span className="text-brand-orange">*</span>}
      </label>
      {textarea ? (
        <textarea
          id={id}
          value={value}
          required={required}
          placeholder={placeholder}
          onChange={(e) => onChange(e.target.value)}
          rows={2}
          className="rounded-lg border border-black/10 px-3.5 py-2.5 text-sm focus:border-brand-orange focus:outline-none focus:ring-1 focus:ring-brand-orange"
        />
      ) : (
        <input
          id={id}
          type={type}
          value={value}
          required={required}
          placeholder={placeholder}
          onChange={(e) => onChange(e.target.value)}
          className="rounded-lg border border-black/10 px-3.5 py-2.5 text-sm focus:border-brand-orange focus:outline-none focus:ring-1 focus:ring-brand-orange"
        />
      )}
    </div>
  );
}
