"use client";

import { FormEvent, useCallback, useEffect, useMemo, useState } from "react";
import { Elements, PaymentElement, useElements, useStripe } from "@stripe/react-stripe-js";
import { loadStripe, type Stripe } from "@stripe/stripe-js";
import { CreditCardIcon } from "@heroicons/react/24/outline";
import { Button } from "@/components/Button";
import { ErrorState } from "@/components/ui/ErrorState";
import { Skeleton } from "@/components/ui/Skeleton";
import { StatusBadge } from "@/components/ui/StatusBadge";
import { ApiError } from "@/lib/api";
import { paymentApi } from "@/lib/api/payments";
import { formatMoneyMinor } from "@/lib/format";
import { buildPaymentFinancialBreakdown } from "@/lib/campaign-detail-ui";
import {
  PAYMENT_AUTHORIZE_CTA,
  PAYMENT_AUTHORIZED_COPY,
  PAYMENT_AUTHORIZED_HELP,
  PAYMENT_BRAND_SUBTOTAL_LABEL,
  PAYMENT_BRAND_TOTAL_LABEL,
  PAYMENT_COMPLETE_CTA,
  PAYMENT_CREATOR_COMPENSATION_LABEL,
  PAYMENT_CREATOR_EARNINGS_LABEL,
  PAYMENT_FEE_ADDED_COPY,
  PAYMENT_FEE_LABEL,
  PAYMENT_HOLD_REMOVED_COPY,
  PAYMENT_PROCESSING_COPY,
  PAYMENT_SETUP_CONSENT,
  PAYMENT_SETUP_EXPLANATION,
  PAYMENT_SUCCESSFUL_COPY,
  PAYMENT_TAXES_PENDING_LABEL,
  PAYMENT_TAXES_PENDING_VALUE,
  PAYMENT_TAXES_LABEL,
  paymentPageViewState,
  paymentStatusBadgeVariant,
  paymentStatusLabel,
} from "@/lib/payments";
import type { MarketplacePayment, PaymentIntentMode } from "@/types/payments";

const stripePromiseCache = new Map<string, Promise<Stripe | null>>();

function stripePromiseFor(publishableKey: string): Promise<Stripe | null> {
  const existing = stripePromiseCache.get(publishableKey);
  if (existing) return existing;
  const promise = loadStripe(publishableKey);
  stripePromiseCache.set(publishableKey, promise);
  return promise;
}

function PaymentSummary({ payment }: { payment: MarketplacePayment }) {
  const breakdown = buildPaymentFinancialBreakdown(payment);
  const feeValue =
    breakdown.platformFeePercent != null
      ? `${breakdown.platformFeePercent}% · ${formatMoneyMinor(breakdown.platformFeeAmount, breakdown.currency)}`
      : formatMoneyMinor(breakdown.platformFeeAmount, breakdown.currency);

  if (breakdown.isLegacyCommission) {
    return (
      <div className="space-y-2 text-[0.8125rem]">
        {(payment.line_items ?? []).map((item) => (
          <div key={item.id} className="flex justify-between gap-3 text-ink-60">
            <span className="min-w-0 truncate">{item.description}</span>
            <span className="shrink-0 tabular-nums text-primary">
              {formatMoneyMinor(item.total_amount, payment.currency)}
            </span>
          </div>
        ))}
        <div
          className={`flex justify-between gap-3 text-ink-60 ${
            (payment.line_items ?? []).length > 0 ? "border-t border-line pt-2" : ""
          }`}
        >
          <span>Creator amount</span>
          <span className="tabular-nums text-primary">
            {formatMoneyMinor(breakdown.creatorAmount, breakdown.currency)}
          </span>
        </div>
        <div className="flex justify-between gap-3 text-ink-60">
          <span>Postvertise commission</span>
          <span className="tabular-nums text-primary">{feeValue}</span>
        </div>
        <div className="flex justify-between gap-3 text-ink-60">
          <span>Creator earnings</span>
          <span className="tabular-nums text-primary">
            {formatMoneyMinor(breakdown.creatorEarnings, breakdown.currency)}
          </span>
        </div>
        <div className="flex justify-between gap-3 border-t border-line pt-2 font-medium text-primary">
          <span>Brand payment</span>
          <span className="tabular-nums">
            {formatMoneyMinor(breakdown.brandPayment, breakdown.currency)}
          </span>
        </div>
        <p className="text-[0.75rem] text-ink-40">
          Historical payment: commission was deducted from the creator agreed amount.
        </p>
      </div>
    );
  }

  return (
    <div className="space-y-2 text-[0.8125rem]">
      {(payment.line_items ?? []).map((item) => (
        <div key={item.id} className="flex justify-between gap-3 text-ink-60">
          <span className="min-w-0 truncate">{item.description}</span>
          <span className="shrink-0 tabular-nums text-primary">
            {formatMoneyMinor(item.total_amount, payment.currency)}
          </span>
        </div>
      ))}
      <div
        className={`flex justify-between gap-3 text-ink-60 ${
          (payment.line_items ?? []).length > 0 ? "border-t border-line pt-2" : ""
        }`}
      >
        <span>{PAYMENT_CREATOR_COMPENSATION_LABEL}</span>
        <span className="tabular-nums text-primary">
          {formatMoneyMinor(breakdown.creatorAmount, breakdown.currency)}
        </span>
      </div>
      <div className="flex justify-between gap-3 text-ink-60">
        <span>{PAYMENT_FEE_LABEL}</span>
        <span className="tabular-nums text-primary">{feeValue}</span>
      </div>
      <div className="flex justify-between gap-3 text-ink-60">
        <span>{PAYMENT_BRAND_SUBTOTAL_LABEL}</span>
        <span className="tabular-nums text-primary">
          {formatMoneyMinor(breakdown.brandSubtotal, breakdown.currency)}
        </span>
      </div>
      <div className="flex justify-between gap-3 text-ink-60">
        <span>{breakdown.taxPending ? PAYMENT_TAXES_PENDING_LABEL : PAYMENT_TAXES_LABEL}</span>
        {breakdown.taxPending || breakdown.totalTaxAmount === null ? (
          <span className="text-ink-40">{PAYMENT_TAXES_PENDING_VALUE}</span>
        ) : (
          <span className="tabular-nums text-primary">
            {formatMoneyMinor(breakdown.totalTaxAmount, breakdown.currency)}
          </span>
        )}
      </div>
      <div className="flex justify-between gap-3 border-t border-line pt-2 font-medium text-primary">
        <span>{PAYMENT_BRAND_TOTAL_LABEL}</span>
        <span className="tabular-nums">
          {formatMoneyMinor(breakdown.brandPayment, breakdown.currency)}
        </span>
      </div>
      <div className="flex justify-between gap-3 text-ink-60">
        <span>{PAYMENT_CREATOR_EARNINGS_LABEL}</span>
        <span className="tabular-nums text-primary">
          {formatMoneyMinor(breakdown.creatorEarnings, breakdown.currency)}
        </span>
      </div>
      <p className="text-[0.75rem] text-ink-40">{PAYMENT_FEE_ADDED_COPY}</p>
    </div>
  );
}

function PaymentElementForm({
  intentMode,
  onProcessing,
  onFailed,
}: {
  intentMode: PaymentIntentMode;
  onProcessing: () => void;
  onFailed: (message: string) => void;
}) {
  const stripe = useStripe();
  const elements = useElements();
  const [submitting, setSubmitting] = useState(false);
  const [consent, setConsent] = useState(intentMode !== "setup");
  const [elementReady, setElementReady] = useState(false);

  async function handleSubmit(event: FormEvent) {
    event.preventDefault();
    if (!stripe || !elements) return;
    if (intentMode === "setup" && !consent) {
      onFailed("Confirm authorization to save this payment method.");
      return;
    }

    setSubmitting(true);
    const result =
      intentMode === "setup"
        ? await stripe.confirmSetup({
            elements,
            redirect: "if_required",
          })
        : await stripe.confirmPayment({
            elements,
            redirect: "if_required",
          });

    if (result.error) {
      onFailed(result.error.message || "Payment could not be completed.");
      setSubmitting(false);
      return;
    }

    // Browser confirmation is not authoritative — show processing until webhook sync.
    onProcessing();
    setSubmitting(false);
  }

  const submitLabel =
    intentMode === "setup"
      ? submitting
        ? "Authorizing…"
        : PAYMENT_AUTHORIZE_CTA
      : submitting
        ? "Confirming…"
        : PAYMENT_COMPLETE_CTA;

  return (
    <form onSubmit={(event) => void handleSubmit(event)} className="space-y-3">
      <div className="min-h-[12rem]">
        <PaymentElement
          options={{ layout: "tabs" }}
          onReady={() => setElementReady(true)}
          onLoadError={(event) => {
            const message =
              event.error?.message ||
              "Unable to load the payment form. Check that STRIPE_SECRET_KEY and STRIPE_PUBLISHABLE_KEY are a matching test (or live) pair from the same Stripe account.";
            onFailed(message);
          }}
        />
      </div>
      {intentMode === "setup" ? (
        <label className="flex items-start gap-2 text-[0.75rem] text-ink-60">
          <input
            type="checkbox"
            className="mt-0.5"
            checked={consent}
            onChange={(event) => setConsent(event.target.checked)}
          />
          <span>{PAYMENT_SETUP_CONSENT}</span>
        </label>
      ) : null}
      <Button
        type="submit"
        size="sm"
        disabled={!stripe || !elementReady || submitting || (intentMode === "setup" && !consent)}
      >
        {submitLabel}
      </Button>
    </form>
  );
}

export function BrandParticipantPaymentPanel({
  campaignId,
  participantId,
  creatorName,
  participantActive,
  paymentConfirmed,
  paymentMethodAuthorized,
}: {
  campaignId: number;
  participantId: number;
  creatorName: string;
  participantActive: boolean;
  paymentConfirmed: boolean;
  paymentMethodAuthorized: boolean;
}) {
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [confirmError, setConfirmError] = useState<string | null>(null);
  const [payment, setPayment] = useState<MarketplacePayment | null>(null);
  const [clientSecret, setClientSecret] = useState<string | null>(null);
  const [publishableKey, setPublishableKey] = useState<string | null>(null);
  const [intentMode, setIntentMode] = useState<PaymentIntentMode | null>(null);
  const [starting, setStarting] = useState(false);

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const existing = await paymentApi.get(campaignId, participantId);
      setPayment(existing);
      if (existing?.status === "succeeded" || existing?.status === "authorized") {
        setClientSecret(null);
        setPublishableKey(null);
        setIntentMode(null);
      }
    } catch (err) {
      setError(err instanceof ApiError ? err.message : "Unable to load payment.");
    } finally {
      setLoading(false);
    }
  }, [campaignId, participantId]);

  useEffect(() => {
    void load();
  }, [load]);

  useEffect(() => {
    if (
      payment?.status !== "processing" &&
      payment?.status !== "requires_setup" &&
      payment?.status !== "action_required"
    ) {
      return;
    }
    const timer = window.setInterval(() => {
      void paymentApi
        .get(campaignId, participantId)
        .then((next) => {
          if (next) setPayment(next);
        })
        .catch(() => {
          /* keep polling quietly */
        });
    }, 3000);
    return () => window.clearInterval(timer);
  }, [payment?.status, campaignId, participantId]);

  async function handleStartPayment() {
    setStarting(true);
    setConfirmError(null);
    setError(null);
    try {
      const result = await paymentApi.create(campaignId, participantId);
      setPayment(result.payment);
      setClientSecret(result.client_secret);
      setPublishableKey(result.publishable_key);
      setIntentMode(result.intent_mode);
    } catch (err) {
      setError(err instanceof ApiError ? err.message : "Unable to start payment authorization.");
    } finally {
      setStarting(false);
    }
  }

  const view = useMemo(
    () =>
      paymentPageViewState({
        loading,
        error,
        payment,
        clientSecret,
        publishableKey,
        intentMode,
        confirmError,
      }),
    [loading, error, payment, clientSecret, publishableKey, intentMode, confirmError],
  );

  if (!participantActive) {
    return null;
  }

  if (view.kind === "loading") {
    return <Skeleton className="mt-2 h-20 w-full" />;
  }

  if (view.kind === "error") {
    return (
      <div className="mt-2">
        <ErrorState
          title="Couldn’t load payment"
          message={view.message}
          retryLabel="Retry"
          onRetry={() => void load()}
        />
      </div>
    );
  }

  if (view.kind === "succeeded" || paymentConfirmed) {
    const succeededPayment = view.kind === "succeeded" ? view.payment : payment;
    return (
      <div className="mt-2 space-y-2 rounded-pv border border-line bg-bg p-3">
        <div className="flex flex-wrap items-center gap-2">
          <StatusBadge variant="success">{PAYMENT_SUCCESSFUL_COPY}</StatusBadge>
          <span className="text-[0.75rem] text-ink-40">for {creatorName}</span>
        </div>
        {succeededPayment ? <PaymentSummary payment={succeededPayment} /> : null}
        <p className="text-[0.75rem] text-ink-40">{PAYMENT_HOLD_REMOVED_COPY}</p>
      </div>
    );
  }

  if (
    view.kind === "authorized" ||
    (paymentMethodAuthorized &&
      view.kind !== "collecting" &&
      view.kind !== "processing" &&
      view.kind !== "action_required" &&
      view.kind !== "failed")
  ) {
    const authorizedPayment = view.kind === "authorized" ? view.payment : payment;
    return (
      <div className="mt-2 space-y-2 rounded-pv border border-line bg-bg p-3">
        <div className="flex flex-wrap items-center gap-2">
          <StatusBadge variant="accent">{PAYMENT_AUTHORIZED_COPY}</StatusBadge>
          <span className="text-[0.75rem] text-ink-40">for {creatorName}</span>
        </div>
        {authorizedPayment ? <PaymentSummary payment={authorizedPayment} /> : null}
        <p className="text-[0.75rem] text-ink-40">{PAYMENT_AUTHORIZED_HELP}</p>
      </div>
    );
  }

  if (view.kind === "action_required") {
    return (
      <div className="mt-2 space-y-2 rounded-pv border border-line bg-bg p-3">
        <StatusBadge variant="warning">{paymentStatusLabel(view.payment.status)}</StatusBadge>
        <PaymentSummary payment={view.payment} />
        <p className="text-[0.75rem] text-ink-40">
          Additional authentication is required. The creator is not paid until this charge succeeds.
        </p>
        <Button size="sm" disabled={starting} onClick={() => void handleStartPayment()}>
          <CreditCardIcon className="size-4" aria-hidden="true" />
          <span>{starting ? "Starting…" : PAYMENT_COMPLETE_CTA}</span>
        </Button>
      </div>
    );
  }

  if (view.kind === "processing") {
    return (
      <div className="mt-2 space-y-2 rounded-pv border border-line bg-bg p-3">
        <StatusBadge variant="accent">{PAYMENT_PROCESSING_COPY}</StatusBadge>
        <PaymentSummary payment={view.payment} />
        <p className="text-[0.75rem] text-ink-40">
          Confirming with Stripe. Status updates when payment is verified — browser return is not final.
        </p>
      </div>
    );
  }

  if (view.kind === "collecting") {
    return (
      <div className="mt-2 space-y-3 rounded-pv border border-line bg-bg p-3">
        <div className="flex flex-wrap items-center gap-2">
          <StatusBadge variant={paymentStatusBadgeVariant(view.payment.status)}>
            {paymentStatusLabel(view.payment.status)}
          </StatusBadge>
        </div>
        <PaymentSummary payment={view.payment} />
        {view.intentMode === "setup" ? (
          <p className="text-[0.75rem] text-ink-40">{PAYMENT_SETUP_EXPLANATION}</p>
        ) : (
          <p className="text-[0.75rem] text-ink-40">
            Additional authentication is required to complete this charge.
          </p>
        )}
        <Elements
          stripe={stripePromiseFor(view.publishableKey)}
          options={{ clientSecret: view.clientSecret }}
        >
          <PaymentElementForm
            intentMode={view.intentMode}
            onProcessing={() => {
              setClientSecret(null);
              setConfirmError(null);
              void load();
            }}
            onFailed={(message) => setConfirmError(message)}
          />
        </Elements>
        {confirmError ? <p className="text-[0.75rem] text-red-700">{confirmError}</p> : null}
      </div>
    );
  }

  if (view.kind === "failed") {
    return (
      <div className="mt-2 space-y-2 rounded-pv border border-line bg-bg p-3">
        <StatusBadge variant="error">{paymentStatusLabel(view.payment.status)}</StatusBadge>
        <PaymentSummary payment={view.payment} />
        <p className="text-[0.75rem] text-red-700">{view.message}</p>
        <p className="text-[0.75rem] text-ink-40">
          Update or authenticate the payment method. The creator is not paid until this charge succeeds.
        </p>
        <Button size="sm" variant="secondary" disabled={starting} onClick={() => void handleStartPayment()}>
          <CreditCardIcon className="size-4" aria-hidden="true" />
          <span>{starting ? "Starting…" : "Update payment method"}</span>
        </Button>
      </div>
    );
  }

  const previewPayment = view.kind === "ready" ? view.payment : null;

  return (
    <div className="mt-2 space-y-2 rounded-pv border border-line bg-bg p-3">
      {previewPayment ? (
        <>
          <StatusBadge variant={paymentStatusBadgeVariant(previewPayment.status)}>
            {paymentStatusLabel(previewPayment.status)}
          </StatusBadge>
          <PaymentSummary payment={previewPayment} />
          <p className="text-[0.75rem] text-ink-40">{PAYMENT_SETUP_EXPLANATION}</p>
        </>
      ) : (
        <p className="text-[0.8125rem] text-ink-60">{PAYMENT_SETUP_EXPLANATION}</p>
      )}
      <Button size="sm" disabled={starting} onClick={() => void handleStartPayment()}>
        <CreditCardIcon className="size-4" aria-hidden="true" />
        <span>{starting ? "Starting…" : PAYMENT_AUTHORIZE_CTA}</span>
      </Button>
    </div>
  );
}
