/**
 * ReferralDashboard — full referral program page for logged-in users.
 *
 * Shows:
 * - ShareInvite card (link + share CTA)
 * - Wallet split tiles: pending vs matured (available)
 * - Stats tiles: pending referees count, qualified count, lifetime earned
 * - Referee list (anonymized: first letter of name + masked phone)
 * - Recent ledger activity (last 5 entries)
 * - Withdraw CTA (KYC-gated; 409 responses handled gracefully)
 *
 * Must be mounted inside a HydratedIsland (wraps with QueryClient).
 */

'use client';

import { useState } from 'react';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useT } from '@/lib/i18n/react';
import { MetricTile } from '@/components/ui/domain/MetricTile';
import { Button } from '@/components/ui/primitives/Button';
import { InlineNotice } from '@/components/ui/feedback/InlineNotice';
import { Skeleton } from '@/components/ui/feedback/Skeleton';
import { ShareInvite } from './ShareInvite';
import { getCsrfToken } from '@/lib/csrf';
import { captureCaught } from '@/lib/observability';
import { DEFAULT_AFFILIATE_CONFIG } from '@/features/affiliate/types';
import type { RefereeEntry, LedgerActivity } from '@/pages/api/referrals/me';
import {
  agorotToShekels,
  formatAgorotDisplay,
  formatAgorotWhole,
  formatAgorotPlain,
} from '@/lib/money.js';
import { EmptyState } from '@/components/ui/feedback/EmptyState';
import { SegmentedControl } from '@/components/ui/primitives/SegmentedControl';
import { useDashboardDensity } from '@/features/dashboards/useDashboardDensity';

interface MeData {
  code: string | null;
  url: string | null;
  pending: number;
  qualified: number;
  balanceAgorot: number;
  lifetimeEarnedAgorot: number;
  pendingAgorot: number;
  maturedAgorot: number;
  referees: RefereeEntry[];
  recentActivity: LedgerActivity[];
}

interface MeResponse {
  ok: true;
  data: MeData;
}

interface WithdrawError {
  code: 'KYC_REQUIRED' | 'WITHDRAW_INELIGIBLE';
}

async function fetchMe(): Promise<MeData> {
  const res = await fetch('/api/referrals/me');
  if (!res.ok) throw new Error('Failed to fetch referral data');
  const json = (await res.json()) as MeResponse;
  return json.data;
}

async function requestWithdraw(): Promise<void> {
  const res = await fetch('/api/referrals/withdraw', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-csrf-token': getCsrfToken(),
    },
  });
  if (!res.ok) {
    const body = (await res.json()) as { ok: false; code: string };
    throw Object.assign(new Error(body.code), { code: body.code });
  }
}

/** Wallet split: pending vs matured tiles — exported for unit testing. */
export function WalletSummary({
  pendingAgorot,
  maturedAgorot,
}: {
  pendingAgorot: number;
  maturedAgorot: number;
}) {
  const t = useT('referrals');
  return (
    <div className="grid grid-cols-2 gap-3">
      <div className="rounded-xl border border-(--color-border) bg-(--color-surface) p-4 text-center">
        <p className="text-text-secondary text-sm">{t('wallet_pending_label')}</p>
        <p className="text-text-primary text-2xl font-semibold tabular-nums">
          {formatAgorotWhole(pendingAgorot)}
        </p>
        <p className="text-text-muted mt-1 text-xs">{t('wallet_pending_hint')}</p>
      </div>
      <div className="rounded-xl border border-(--color-border) bg-(--color-surface) p-4 text-center">
        <p className="text-text-secondary text-sm">{t('wallet_available_label')}</p>
        <p className="text-text-primary text-2xl font-semibold tabular-nums">
          {(() => {
            const display = formatAgorotDisplay(maturedAgorot);
            if (typeof display === 'object' && display.isDebt) {
              const amount = formatAgorotPlain(display.debtAgorot);
              return (
                <span className="text-(--color-text-muted)">
                  {t('balance_debt_label')}
                  <span className="mt-0.5 block text-xs">
                    {t('balance_debt_detail').replace('{{amount}}', amount)}
                  </span>
                </span>
              );
            }
            return <span>{display as string}</span>;
          })()}
        </p>
        <p className="text-text-muted mt-1 text-xs">{t('wallet_available_hint')}</p>
      </div>
    </div>
  );
}

/** Single referee row (anonymized). */
function RefereeRow({ referee, dense = false }: { referee: RefereeEntry; dense?: boolean }) {
  const t = useT('referrals');
  const statusKey =
    referee.status === 'qualified' ? 'referee_status_qualified' : 'referee_status_pending';
  return (
    <li
      className={
        dense
          ? 'flex items-center justify-between gap-2 py-1.5'
          : 'flex items-center justify-between gap-2 py-2'
      }
    >
      <span className="text-text-primary text-sm font-medium" dir="ltr">
        {referee.maskedName} · {referee.maskedPhone}
      </span>
      <span
        className={
          referee.status === 'qualified'
            ? 'text-success text-xs font-semibold'
            : 'text-text-muted text-xs'
        }
        aria-label={t(statusKey)}
      >
        {t(statusKey)}
      </span>
    </li>
  );
}

/** Recent ledger activity row. */
function ActivityRow({ entry, dense = false }: { entry: LedgerActivity; dense?: boolean }) {
  const t = useT('referrals');
  const isCredit = entry.amountAgorot > 0;
  return (
    <li
      className={
        dense
          ? 'flex items-center justify-between gap-2 py-1.5'
          : 'flex items-center justify-between gap-2 py-2'
      }
    >
      <span className="text-text-secondary text-xs">
        {t(`activity_${entry.entryType}` as 'activity_referral_reward')}
      </span>
      <span
        className={
          isCredit
            ? 'text-success text-sm font-semibold tabular-nums'
            : 'text-danger text-sm font-semibold tabular-nums'
        }
      >
        {isCredit ? '+' : ''}
        {formatAgorotWhole(entry.amountAgorot)}
      </span>
    </li>
  );
}

/** ReferralDashboard — mounted on /referrals page. */
export function ReferralDashboard() {
  const t = useT('referrals');
  const queryClient = useQueryClient();
  const { density, setDensity } = useDashboardDensity('dashboard-density:referrals');
  const [withdrawStatus, setWithdrawStatus] = useState<
    'idle' | 'kyc_required' | 'ineligible' | 'success' | 'error'
  >('idle');

  const { data, isLoading, isError } = useQuery({
    queryKey: ['referrals', 'me'],
    queryFn: fetchMe,
    staleTime: 60_000,
    retry: 1,
  });

  const withdrawMutation = useMutation({
    mutationFn: requestWithdraw,
    onSuccess: () => {
      setWithdrawStatus('success');
      void queryClient.invalidateQueries({ queryKey: ['referrals', 'me'] });
    },
    onError: (err) => {
      const e = err as Error & Partial<WithdrawError>;
      if (e.code === 'KYC_REQUIRED') {
        setWithdrawStatus('kyc_required');
      } else if (e.code === 'WITHDRAW_INELIGIBLE') {
        setWithdrawStatus('ineligible');
      } else {
        setWithdrawStatus('error');
        captureCaught(err, {
          scope: 'features.referrals.ReferralDashboard.withdraw',
          severity: 'warning',
        });
      }
    },
  });

  return (
    <main id="main" className="mx-auto flex max-w-2xl flex-col gap-6 px-4 py-6">
      {/* Page heading */}
      <header>
        <h1 className="text-text-primary text-xl font-extrabold">{t('page_title')}</h1>
        <p className="text-text-secondary mt-1 text-sm">{t('page_description')}</p>
      </header>

      {!isLoading &&
        !isError &&
        data &&
        (() => {
          const balanceDisplay = formatAgorotDisplay(data.balanceAgorot);
          const balanceIsDebt = typeof balanceDisplay === 'object';
          const balanceValue = balanceIsDebt ? (
            <span className="text-text-muted">
              {t('balance_debt_label')}
              <span className="mt-0.5 block text-xs">
                {t('balance_debt_detail').replace(
                  '{{amount}}',
                  formatAgorotPlain(balanceDisplay.debtAgorot),
                )}
              </span>
            </span>
          ) : (
            balanceDisplay
          );

          return (
            <MetricTile
              label={t('hero_available_credit')}
              value={balanceValue}
              countUpValue={balanceIsDebt ? undefined : agorotToShekels(data.balanceAgorot)}
              formatCountUpValue={(value) => {
                const display = formatAgorotDisplay(Math.round(value * 100));
                return typeof display === 'string'
                  ? display
                  : formatAgorotPlain(display.debtAgorot);
              }}
              periodLabel={t('hero_period_current_balance')}
            />
          );
        })()}

      {/* Share / invite card */}
      <section id="referral-share">
        <ShareInvite />
      </section>

      {/* Wallet split tiles */}
      {isLoading ? (
        <div className="grid grid-cols-2 gap-3" aria-busy="true">
          <Skeleton className="h-24 rounded-xl" />
          <Skeleton className="h-24 rounded-xl" />
        </div>
      ) : !isError && data ? (
        <WalletSummary pendingAgorot={data.pendingAgorot} maturedAgorot={data.maturedAgorot} />
      ) : null}

      {/* Stats tiles: referral counts + lifetime */}
      {isLoading ? (
        <div className="grid grid-cols-2 gap-3" aria-busy="true" aria-label={t('page_title')}>
          {[0, 1, 2, 3].map((i) => (
            <Skeleton key={i} className="h-20 rounded-xl" />
          ))}
        </div>
      ) : isError ? (
        <InlineNotice
          tone="danger"
          title={t('error_load_title')}
          description={t('error_load_body')}
        />
      ) : (
        <div className="grid grid-cols-2 gap-3">
          <MetricTile value={data!.pending.toString()} label={t('pending_label')} tone="default" />
          <MetricTile
            value={data!.qualified.toString()}
            label={t('qualified_label')}
            tone="success"
          />
          <MetricTile
            value={formatAgorotWhole(data!.balanceAgorot)}
            label={t('balance_label')}
            tone={data!.balanceAgorot > 0 ? 'success' : 'default'}
          />
          <MetricTile
            value={formatAgorotWhole(data!.lifetimeEarnedAgorot)}
            label={t('lifetime_label')}
            tone="default"
          />
        </div>
      )}

      {/* Referee list */}
      {!isLoading && !isError && data && (
        <section aria-labelledby="referees-heading" className="flex flex-col gap-2">
          <div className="flex flex-wrap items-center justify-between gap-3">
            <h2 id="referees-heading" className="text-text-primary text-base font-bold">
              {t('referees_heading')}
            </h2>
            <SegmentedControl
              aria-label={t('density_label')}
              size="sm"
              value={density}
              onChange={(value) => setDensity(value as 'comfortable' | 'dense')}
              options={[
                { value: 'comfortable', label: t('density_comfortable') },
                { value: 'dense', label: t('density_dense') },
              ]}
            />
          </div>
          {data.referees.length === 0 ? (
            <EmptyState
              title={t('empty_referees_title')}
              description={t('no_referrals_yet')}
              action={
                <Button variant="secondary" size="sm" asChild>
                  <a href="#referral-share">{t('share_cta')}</a>
                </Button>
              }
            />
          ) : (
            <ul
              className="divide-y divide-(--color-border) rounded-xl border border-(--color-border) bg-(--color-surface) px-4"
              aria-label={t('referees_heading')}
            >
              {data.referees.map((r) => (
                <RefereeRow
                  key={`${r.maskedPhone}-${r.status}-${r.qualifiedAt ?? 'pending'}`}
                  referee={r}
                  dense={density === 'dense'}
                />
              ))}
            </ul>
          )}
        </section>
      )}

      {/* Recent ledger activity */}
      {!isLoading && !isError && data && data.recentActivity.length > 0 && (
        <section aria-labelledby="activity-heading" className="flex flex-col gap-2">
          <h2 id="activity-heading" className="text-text-primary text-base font-bold">
            {t('recent_activity_heading')}
          </h2>
          <ul
            className="divide-y divide-(--color-border) rounded-xl border border-(--color-border) bg-(--color-surface) px-4"
            aria-label={t('recent_activity_heading')}
          >
            {data.recentActivity.map((entry) => (
              <ActivityRow key={entry.id} entry={entry} dense={density === 'dense'} />
            ))}
          </ul>
        </section>
      )}

      {/* Affiliate window status */}
      {!isLoading && !isError && (
        <div
          className="bg-surface-raised flex items-center justify-between gap-2 rounded-xl px-4 py-3"
          aria-label={t('affiliate_window_label')}
        >
          <span className="text-text-secondary text-sm font-medium">
            {t('affiliate_window_label')}
          </span>
          <span className="text-text-primary text-sm font-semibold">
            {t('affiliate_window_inactive')}
          </span>
        </div>
      )}

      {/* Hold period note — rate from env/config; dynamic API rate deferred */}
      {!isLoading && !isError && (
        <div className="border-border-subtle bg-surface-raised rounded-xl border p-4">
          <p className="text-text-primary text-sm font-semibold">{t('deferred_title')}</p>
          <ul className="text-text-muted mt-2 flex list-disc flex-col gap-1 ps-5 text-sm">
            <li>{t('deferred_dynamic_affiliate_window')}</li>
            <li>
              {t('hold_note').replace('{{holdDays}}', String(DEFAULT_AFFILIATE_CONFIG.holdDays))}
            </li>
          </ul>
        </div>
      )}

      {/* Withdraw section */}
      <section aria-labelledby="withdraw-heading" className="flex flex-col gap-3">
        <h2 id="withdraw-heading" className="text-text-primary text-base font-bold">
          {t('withdraw_cta')}
        </h2>
        <p className="text-text-secondary text-sm">{t('withdraw_min_notice')}</p>

        {withdrawStatus === 'kyc_required' && (
          <InlineNotice
            tone="warning"
            title={t('kyc_required_title')}
            description={t('kyc_required_body')}
          />
        )}
        {withdrawStatus === 'ineligible' && (
          <InlineNotice
            tone="info"
            title={t('withdraw_ineligible')}
            description={t('withdraw_min_notice')}
          />
        )}
        {withdrawStatus === 'error' && (
          <InlineNotice
            tone="danger"
            title={t('withdraw_error_title')}
            description={t('withdraw_ineligible')}
          />
        )}
        {withdrawStatus === 'success' && (
          <InlineNotice
            tone="success"
            title={t('withdraw_success_title')}
            description={t('withdraw_success_title')}
          />
        )}

        <Button
          variant="secondary"
          size="md"
          onClick={() => {
            setWithdrawStatus('idle');
            withdrawMutation.mutate();
          }}
          disabled={withdrawMutation.isPending}
          aria-label={t('withdraw_cta')}
        >
          {t('withdraw_cta')}
        </Button>
      </section>
    </main>
  );
}
