'use client';

/**
 * StripeVendorDashboard — Stripe Connect embedded dashboard island.
 *
 * Three render states:
 *   A: no stripeAccountId — vendor never started onboarding
 *   B: account exists but charges not yet enabled — KYC pending
 *   C: charges enabled — embedded Stripe Connect dashboard
 */

import { useState, useEffect, useRef, useCallback } from 'react';
import { loadConnectAndInitialize } from '@stripe/connect-js/pure';
import type { StripeConnectInstance } from '@stripe/connect-js/pure';
import {
  ConnectComponentsProvider,
  ConnectPayouts,
  ConnectPayments,
} from '@stripe/react-connect-js';
import { Button } from '@/components/ui/primitives/Button';
import { ErrorBoundary } from '@/components/ui/feedback/ErrorBoundary';
import { Spinner } from '@/components/ui/feedback/Spinner';
import { InlineNotice } from '@/components/ui/feedback/InlineNotice';
import { useT, useLocale } from '@/lib/i18n/react';
import { getCsrfToken } from '@/lib/csrf';
import { captureCaught } from '@/lib/observability';

// ─── Types ────────────────────────────────────────────────────────────────────

export interface StripeVendorDashboardProps {
  publishableKey: string;
  stripeConnected: boolean;
  stripeAccountId: string | null;
}

// ─── Inner component ──────────────────────────────────────────────────────────

function StripeVendorDashboardInner({
  publishableKey,
  stripeConnected,
  stripeAccountId,
}: StripeVendorDashboardProps) {
  const t = useT('vendor_earnings');
  const { locale } = useLocale();

  const [connected, setConnected] = useState(stripeConnected);
  const [syncing, setSyncing] = useState(false);

  const [instance, setInstance] = useState<StripeConnectInstance | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Clean up instance on unmount to avoid memory leaks
  useEffect(() => {
    return () => {
      setInstance(null);
    };
  }, []);

  // Sync: POST /api/vendor/stripe/sync to check live Stripe state
  const doSync = useCallback(async () => {
    if (syncing) return;
    setSyncing(true);
    try {
      const res = await fetch('/api/vendor/stripe/sync', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-csrf-token': getCsrfToken(),
        },
      });
      if (res.ok) {
        const json = (await res.json()) as { chargesEnabled?: boolean };
        if (json.chargesEnabled) {
          setConnected(true);
        }
      }
    } catch (err) {
      captureCaught(err, {
        scope: 'features.vendor-earnings.StripeVendorDashboard.sync',
        severity: 'warning',
      });
    } finally {
      setSyncing(false);
    }
  }, [syncing]);

  // Fire once on mount when account exists but not yet connected
  const didSync = useRef(false);
  useEffect(() => {
    if (!stripeAccountId || connected || didSync.current) return;
    didSync.current = true;
    void doSync();
  }, [stripeAccountId, connected, doSync]);

  // ── State A: no account — vendor never started onboarding ────────────────
  if (!stripeAccountId) {
    return (
      <div className="bg-surface-raised border-border-default rounded-lg border p-6 text-center">
        <p className="text-text-secondary mb-4">{t('stripe_not_connected')}</p>
        <a
          href="/vendor/settings/payments"
          className="text-text-link hover:text-text-link-hover text-sm font-medium underline transition-colors duration-[var(--duration-fast)]"
        >
          {t('stripe_connect_cta')}
        </a>
      </div>
    );
  }

  // ── State B: account exists, charges not yet enabled ─────────────────────
  if (!connected) {
    if (syncing) {
      return (
        <div className="bg-surface-raised border-border-default flex items-center justify-center rounded-lg border p-12">
          <Spinner size="lg" />
        </div>
      );
    }

    return (
      <div className="flex flex-col gap-4 p-6">
        <InlineNotice
          tone="warning"
          title={t('stripe_account_pending_title')}
          description={t('stripe_account_pending_body')}
        />
        <div className="flex gap-3">
          <Button variant="secondary" size="sm" onClick={() => void doSync()} disabled={syncing}>
            {t('stripe_refresh_status')}
          </Button>
          <Button variant="ghost" size="sm" asChild>
            <a href="/vendor/settings/payments">{t('stripe_connect_cta')}</a>
          </Button>
        </div>
      </div>
    );
  }

  // ── State C: connected — existing embedded dashboard ─────────────────────

  async function handleLoadStripe() {
    setLoading(true);
    setError(null);
    try {
      const stripeInstance = loadConnectAndInitialize({
        publishableKey,
        locale,
        fetchClientSecret: async () => {
          const res = await fetch('/api/vendor/stripe-session', {
            method: 'POST',
            headers: {
              'Content-Type': 'application/json',
              'x-csrf-token': getCsrfToken(),
            },
          });
          if (!res.ok) {
            const body = (await res.json().catch((parseErr: unknown) => {
              captureCaught(parseErr, {
                scope: 'features.vendor-earnings.StripeVendorDashboard.parseBody',
                severity: 'warning',
              });
              return {};
            })) as { error?: string };
            throw new Error(body.error ?? `HTTP ${res.status}`);
          }
          const json = (await res.json()) as { ok: boolean; clientSecret: string };
          return json.clientSecret;
        },
      });
      setInstance(stripeInstance);
    } catch (err) {
      captureCaught(err, {
        scope: 'features.vendor-earnings.StripeVendorDashboard',
        severity: 'error',
      });
      setError(err instanceof Error ? err.message : 'Failed to load Stripe');
    } finally {
      setLoading(false);
    }
  }

  if (error) {
    return (
      <div className="bg-surface-raised border-border-default rounded-lg border p-6">
        <p className="text-semantic-error-600 mb-4 text-sm">{t('stripe_load_error')}</p>
        <Button variant="secondary" size="sm" onClick={() => void handleLoadStripe()}>
          {t('stripe_retry')}
        </Button>
      </div>
    );
  }

  if (loading) {
    return (
      <div className="bg-surface-raised border-border-default flex items-center justify-center rounded-lg border p-12">
        <Spinner size="lg" />
        <span className="text-text-secondary ms-3 text-sm">{t('stripe_loading')}</span>
      </div>
    );
  }

  if (!instance) {
    return (
      <div className="bg-surface-raised border-border-default rounded-lg border p-6 text-center">
        <p className="text-text-secondary mb-4 text-sm">{t('stripe_load_explainer')}</p>
        <Button variant="secondary" size="md" onClick={() => void handleLoadStripe()}>
          {t('stripe_load_cta')}
        </Button>
      </div>
    );
  }

  return (
    <ConnectComponentsProvider connectInstance={instance}>
      <div className="space-y-6">
        <section aria-labelledby="stripe-payouts-heading">
          <h2 id="stripe-payouts-heading" className="text-text-primary mb-3 text-lg font-semibold">
            {t('stripe_payouts_title')}
          </h2>
          <ConnectPayouts />
        </section>
        <section aria-labelledby="stripe-payments-heading">
          <h2 id="stripe-payments-heading" className="text-text-primary mb-3 text-lg font-semibold">
            {t('stripe_payments_title')}
          </h2>
          <ConnectPayments />
        </section>
      </div>
    </ConnectComponentsProvider>
  );
}

// ─── Public export (wrapped in ErrorBoundary) ─────────────────────────────────

export function StripeVendorDashboard(props: StripeVendorDashboardProps) {
  return (
    <ErrorBoundary>
      <StripeVendorDashboardInner {...props} />
    </ErrorBoundary>
  );
}
