"use client";

import { useCallback, useEffect, useState } from "react";
import {
  ConnectAccountManagement,
  ConnectAccountOnboarding,
  ConnectComponentsProvider,
} from "@stripe/react-connect-js";
import { loadConnectAndInitialize } from "@stripe/connect-js/pure";
import type { StripeConnectInstance } from "@stripe/connect-js";
import { Button } from "@/components/Button";
import { DashboardPageContainer } from "@/components/dashboard/DashboardPageContainer";
import { DashboardShell } from "@/components/dashboard/DashboardShell";
import { ConfirmDialog } from "@/components/ui/ConfirmDialog";
import { ErrorState } from "@/components/ui/ErrorState";
import { PageHeader, SectionHeader } from "@/components/ui/PageHeader";
import { StatusBadge } from "@/components/ui/StatusBadge";
import { ApiError } from "@/lib/api";
import { payoutApi } from "@/lib/api/payouts";
import {
  PAYOUT_EXPLANATION,
  payoutManageActionLabel,
  payoutPageViewState,
  payoutPrimaryActionLabel,
  payoutReadinessBadgeVariant,
  payoutReadinessLabel,
  payoutRemoveActionLabel,
  payoutShowsReadyCheck,
} from "@/lib/payouts";
import type { PayoutAccount, PayoutOnboardingSession, PayoutSessionFlow } from "@/types/payouts";

const CREATOR_ONLY = ["creator"] as const;

export function DashboardPayoutsSettingsPage() {
  return (
    <DashboardShell title="Payouts" allowedAccountTypes={CREATOR_ONLY}>
      {() => <PayoutsSettingsContent />}
    </DashboardShell>
  );
}

function PayoutsSettingsContent() {
  const [account, setAccount] = useState<PayoutAccount | null>(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [actionError, setActionError] = useState<string | null>(null);
  const [starting, setStarting] = useState(false);
  const [syncing, setSyncing] = useState(false);
  const [removing, setRemoving] = useState(false);
  const [confirmRemove, setConfirmRemove] = useState(false);
  const [onboarding, setOnboarding] = useState<PayoutOnboardingSession | null>(null);
  const [connectInstance, setConnectInstance] = useState<StripeConnectInstance | null>(null);

  const loadAccount = useCallback(async () => {
    setLoading(true);
    setError(null);

    try {
      const next = await payoutApi.getAccount();
      setAccount(next);
    } catch (caught) {
      const message =
        caught instanceof ApiError ? caught.message : "Unable to load payout settings.";
      setError(message);
      setAccount(null);
    } finally {
      setLoading(false);
    }
  }, []);

  const syncAccount = useCallback(async () => {
    setSyncing(true);
    setActionError(null);

    try {
      const next = await payoutApi.syncAccount();
      setAccount(next);
    } catch (caught) {
      const message =
        caught instanceof ApiError ? caught.message : "Unable to refresh payout status.";
      setActionError(message);
    } finally {
      setSyncing(false);
    }
  }, []);

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

  useEffect(() => {
    if (typeof window === "undefined") {
      return;
    }

    const params = new URLSearchParams(window.location.search);
    const isReturn = params.get("stripe_return") === "1";
    const isRefresh = params.get("stripe_refresh") === "1";

    if (!isReturn && !isRefresh) {
      return;
    }

    let cancelled = false;

    const clearStripeQuery = () => {
      const url = new URL(window.location.href);
      url.searchParams.delete("stripe_return");
      url.searchParams.delete("stripe_refresh");
      window.history.replaceState({}, "", url.pathname + url.search);
    };

    void (async () => {
      // Stripe refresh_url: link expired or reused — mint a new Account Link and redirect.
      if (isRefresh) {
        setStarting(true);
        setActionError(null);
        clearStripeQuery();

        try {
          const response = await payoutApi.createOnboardingSession({ flow: "onboarding" });
          if (cancelled) {
            return;
          }
          setAccount(response.payout_account);

          if (response.onboarding.mode === "account_link" && response.onboarding.url) {
            window.location.assign(response.onboarding.url);
            return;
          }

          setOnboarding(response.onboarding);
        } catch (caught) {
          if (!cancelled) {
            setActionError(
              caught instanceof ApiError
                ? caught.message
                : "Unable to restart payout setup. Please try again.",
            );
          }
        } finally {
          if (!cancelled) {
            setStarting(false);
          }
        }
        return;
      }

      // stripe_return: sync status only (browser return is not authoritative readiness).
      await syncAccount();
      if (!cancelled) {
        clearStripeQuery();
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [syncAccount]);

  useEffect(() => {
    if (!onboarding || onboarding.mode !== "embedded") {
      setConnectInstance(null);
      return;
    }

    const publishableKey = onboarding.publishable_key;
    const flow = onboarding.flow;
    if (!publishableKey) {
      setConnectInstance(null);
      return;
    }

    let cancelled = false;

    try {
      // Stripe requires fetchClientSecret to mint a fresh Account Session each call
      // (initial load + expiry refresh). Reusing a static secret causes auth failures.
      const instance = loadConnectAndInitialize({
        publishableKey,
        fetchClientSecret: async () => {
          const response = await payoutApi.createOnboardingSession({ flow });
          if (response.onboarding.mode !== "embedded" || !response.onboarding.client_secret) {
            throw new Error("Embedded payout session unavailable.");
          }
          if (!cancelled) {
            setAccount(response.payout_account);
          }
          return response.onboarding.client_secret;
        },
      });

      if (!cancelled) {
        setConnectInstance(instance);
      }
    } catch {
      if (!cancelled) {
        setActionError("Unable to start embedded payout setup. Please try again.");
        setConnectInstance(null);
      }
    }

    return () => {
      cancelled = true;
    };
  }, [onboarding]);

  const startSession = useCallback(async (flow: PayoutSessionFlow) => {
    setStarting(true);
    setActionError(null);

    try {
      const response = await payoutApi.createOnboardingSession({ flow });
      setAccount(response.payout_account);

      if (response.onboarding.mode === "account_link" && response.onboarding.url) {
        window.location.assign(response.onboarding.url);
        return;
      }

      setOnboarding(response.onboarding);
    } catch (caught) {
      const message =
        caught instanceof ApiError
          ? caught.message
          : flow === "manage"
            ? "Unable to open payout details."
            : "Unable to start payout setup.";
      setActionError(message);
    } finally {
      setStarting(false);
    }
  }, []);

  const closeEmbeddedSession = useCallback(() => {
    setOnboarding(null);
    setConnectInstance(null);
    void syncAccount();
  }, [syncAccount]);

  const removeAccount = useCallback(async () => {
    setRemoving(true);
    setActionError(null);

    try {
      const next = await payoutApi.removeAccount();
      setAccount(next);
      setOnboarding(null);
      setConnectInstance(null);
      setConfirmRemove(false);
    } catch (caught) {
      let message = "Unable to remove payment gateway.";
      if (caught instanceof ApiError) {
        const fieldMessage = caught.errors.payout_account?.[0];
        message =
          typeof fieldMessage === "string" && fieldMessage.trim() !== ""
            ? fieldMessage
            : caught.message;
      }
      setActionError(message);
      setConfirmRemove(false);
    } finally {
      setRemoving(false);
    }
  }, []);

  const view = payoutPageViewState({
    loading,
    error,
    readiness: account?.readiness ?? null,
  });

  const actionLabel = account ? payoutPrimaryActionLabel(account.readiness) : null;
  const manageLabel = account ? payoutManageActionLabel(account.readiness) : null;
  const removeLabel = account ? payoutRemoveActionLabel(account.connected) : null;
  const embeddedOpen = onboarding?.mode === "embedded" && connectInstance !== null;
  const actionsBusy = starting || syncing || removing;

  return (
    <DashboardPageContainer className="max-w-2xl px-4 py-8 sm:px-6">
      <PageHeader description="Manage the payout account used for creator campaign payments." />

      <section aria-labelledby="payouts-heading" className="space-y-4">
        <SectionHeader
          id="payouts-heading"
          title="Payouts"
          description={PAYOUT_EXPLANATION}
        />

        {view.kind === "loading" ? (
          <div className="h-24 animate-pulse rounded-pv border border-line bg-line/40" aria-hidden="true" />
        ) : null}

        {view.kind === "error" ? (
          <ErrorState
            title="Unable to load payout settings"
            message={view.message}
            onRetry={() => {
              void loadAccount();
            }}
          />
        ) : null}

        {view.kind === "ready" && account ? (
          <div className="space-y-4 rounded-pv border border-line bg-surface p-5">
            <div className="flex flex-wrap items-center gap-2">
              <p className="text-[0.8125rem] text-ink-60">Status</p>
              <StatusBadge variant={payoutReadinessBadgeVariant(account.readiness)}>
                {payoutReadinessLabel(account.readiness)}
              </StatusBadge>
            </div>

            {payoutShowsReadyCheck(account.readiness) ? (
              <p className="text-[0.9375rem] font-medium text-primary" role="status">
                ✓ Ready for payouts
              </p>
            ) : null}

            {account.readiness === "verification_pending" ? (
              <p className="text-[0.8125rem] text-ink-60">
                Stripe is reviewing your payout account. Status updates when verification finishes.
              </p>
            ) : null}

            {account.readiness === "ready" && !embeddedOpen ? (
              <p className="text-[0.8125rem] text-ink-60">
                Need to change your bank account or personal details? Update them securely through
                Stripe.
              </p>
            ) : null}

            {actionError ? (
              <p className="text-[0.8125rem] text-red-700" role="alert">
                {actionError}
              </p>
            ) : null}

            <div className="flex flex-wrap gap-2">
              {actionLabel ? (
                <Button
                  type="button"
                  size="sm"
                  disabled={actionsBusy}
                  aria-busy={starting}
                  onClick={() => {
                    void startSession("onboarding");
                  }}
                >
                  {starting ? "Starting…" : actionLabel}
                </Button>
              ) : null}

              {manageLabel ? (
                <Button
                  type="button"
                  size="sm"
                  variant={actionLabel ? "secondary" : "primary"}
                  disabled={actionsBusy}
                  aria-busy={starting}
                  onClick={() => {
                    void startSession("manage");
                  }}
                >
                  {starting ? "Opening…" : manageLabel}
                </Button>
              ) : null}

              {account.connected ? (
                <Button
                  type="button"
                  size="sm"
                  variant="secondary"
                  disabled={actionsBusy}
                  aria-busy={syncing}
                  onClick={() => {
                    void syncAccount();
                  }}
                >
                  {syncing ? "Refreshing…" : "Refresh status"}
                </Button>
              ) : null}

              {removeLabel ? (
                <Button
                  type="button"
                  size="sm"
                  variant="secondary"
                  className="border-red-300 text-red-700 hover:border-red-700"
                  disabled={actionsBusy}
                  onClick={() => {
                    setActionError(null);
                    setConfirmRemove(true);
                  }}
                >
                  {removeLabel}
                </Button>
              ) : null}
            </div>

            {embeddedOpen && connectInstance ? (
              <div className="mt-2 space-y-3 border-t border-line pt-4">
                <ConnectComponentsProvider connectInstance={connectInstance}>
                  {onboarding?.component === "account_management" ? (
                    <ConnectAccountManagement />
                  ) : (
                    <ConnectAccountOnboarding onExit={closeEmbeddedSession} />
                  )}
                </ConnectComponentsProvider>

                {onboarding?.component === "account_management" ? (
                  <Button type="button" size="sm" variant="secondary" onClick={closeEmbeddedSession}>
                    Done
                  </Button>
                ) : null}
              </div>
            ) : null}
          </div>
        ) : null}
      </section>

      {confirmRemove ? (
        <ConfirmDialog
          title="Remove payment gateway?"
          description="This disconnects Stripe payouts from Postvertise. You can set up payouts again later. Any Stripe Connect account cleanup is attempted automatically."
          confirmLabel="Remove payment gateway"
          busy={removing}
          busyLabel="Removing…"
          onCancel={() => {
            if (!removing) {
              setConfirmRemove(false);
            }
          }}
          onConfirm={() => {
            void removeAccount();
          }}
        />
      ) : null}
    </DashboardPageContainer>
  );
}
