'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { useRouter } from 'next/navigation';
import ApiErrorAlert from '@/app/components/ApiErrorAlert';
import { getResponseErrorTextWithRequestId } from '@/lib/api-client';
import { formatUsdCents } from '@/lib/billing/currency';
import { getPlanCatalogItem } from '@/lib/plans/catalog';
import { formatDateMoscow, formatTimeMoscow } from '@/lib/time';
import type { PlanId } from '@/lib/plans/types';

type BillingInterval = 'MONTHLY' | 'YEARLY';
type BillingInvoiceStatus = 'PENDING' | 'PAID' | 'EXPIRED' | 'CANCELLED' | 'FAILED';

type CheckoutInvoice = {
  id: string;
  status: BillingInvoiceStatus;
  amountUsdCents: number;
  invoiceUrl: string | null;
  miniAppInvoiceUrl: string | null;
  webAppInvoiceUrl: string | null;
  expiresAt: string | null;
  paidAt?: string | null;
};

type CheckoutCreateResponse = {
  invoice: CheckoutInvoice;
  reused: boolean;
};

type InvoiceStatusResponse = {
  invoice: {
    id: string;
    status: BillingInvoiceStatus;
    expiresAt: string | null;
    paidAt: string | null;
  };
};

type BillingCheckoutCardProps = {
  plan: PlanId;
  interval: BillingInterval;
};

const POLL_INTERVAL_MS = 5000;

function getStatusLabel(status: BillingInvoiceStatus) {
  if (status === 'PENDING') return 'Ожидает оплаты';
  if (status === 'PAID') return 'Оплачен';
  if (status === 'EXPIRED') return 'Истёк';
  if (status === 'CANCELLED') return 'Отменён';
  return 'Ошибка';
}

function getPeriodLabel(interval: BillingInterval) {
  return interval === 'YEARLY' ? 'Годовая подписка' : 'Месячная подписка';
}

function formatDateTime(value: string | null) {
  if (!value) {
    return '—';
  }

  return `${formatDateMoscow(value)} ${formatTimeMoscow(value, { hour: '2-digit', minute: '2-digit' })}`;
}

function formatRemainingTime(milliseconds: number) {
  const totalMinutes = Math.floor(milliseconds / 60_000);
  if (totalMinutes <= 0) {
    return 'меньше минуты';
  }

  const days = Math.floor(totalMinutes / 1440);
  const hours = Math.floor((totalMinutes % 1440) / 60);
  const minutes = totalMinutes % 60;
  const parts: string[] = [];

  if (days > 0) {
    parts.push(`${days} дн`);
  }
  if (hours > 0) {
    parts.push(`${hours} ч`);
  }
  if (minutes > 0 || parts.length === 0) {
    parts.push(`${minutes} мин`);
  }

  return parts.join(' ');
}

function getInvoiceOpenUrl(invoice: CheckoutInvoice) {
  return invoice.invoiceUrl ?? invoice.miniAppInvoiceUrl ?? invoice.webAppInvoiceUrl;
}

export default function BillingCheckoutCard({ plan, interval }: BillingCheckoutCardProps) {
  const router = useRouter();
  const planMeta = getPlanCatalogItem(plan);
  const redirectedRef = useRef(false);
  const cancelRedirectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);

  const [invoice, setInvoice] = useState<CheckoutInvoice | null>(null);
  const [isCreating, setIsCreating] = useState(false);
  const [isCancelling, setIsCancelling] = useState(false);
  const [errorMessage, setErrorMessage] = useState('');
  const [retryToken, setRetryToken] = useState(0);
  const [nowTs, setNowTs] = useState(() => Date.now());

  const amountUsdCents = useMemo(() => invoice?.amountUsdCents ?? null, [invoice?.amountUsdCents]);

  const scheduleSuccessRedirect = useCallback(() => {
    if (redirectedRef.current) {
      return;
    }

    redirectedRef.current = true;
    router.replace('/profile?billing=success', { scroll: false });
  }, [router]);

  const clearCancelRedirect = useCallback(() => {
    if (!cancelRedirectTimerRef.current) {
      return;
    }

    clearTimeout(cancelRedirectTimerRef.current);
    cancelRedirectTimerRef.current = null;
  }, []);

  const scheduleCancelRedirect = useCallback(() => {
    if (cancelRedirectTimerRef.current) {
      return;
    }

    cancelRedirectTimerRef.current = setTimeout(() => {
      router.replace('/profile', { scroll: false });
    }, 5000);
  }, [router]);

  const createInvoice = useCallback(async () => {
    setIsCreating(true);
    setErrorMessage('');
    clearCancelRedirect();
    setInvoice(null);

    try {
      const response = await fetch('/api/billing/checkout', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ plan, interval }),
      });

      if (!response.ok) {
        throw new Error(await getResponseErrorTextWithRequestId(response, 'Не удалось создать счёт на оплату'));
      }

      const data = await response.json() as CheckoutCreateResponse;
      setInvoice(data.invoice);
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : 'Не удалось создать счёт на оплату');
    } finally {
      setIsCreating(false);
    }
  }, [clearCancelRedirect, interval, plan]);

  const refreshInvoiceStatus = useCallback(async (invoiceId: string) => {
    try {
      const response = await fetch(`/api/billing/invoices/${invoiceId}`, {
        cache: 'no-store',
      });

      if (!response.ok) {
        throw new Error(await getResponseErrorTextWithRequestId(response, 'Не удалось получить статус счёта'));
      }

      const data = await response.json() as InvoiceStatusResponse;
      setInvoice((current) => {
        if (!current) {
          return current;
        }

        return {
          ...current,
          status: data.invoice.status,
          expiresAt: data.invoice.expiresAt,
          paidAt: data.invoice.paidAt,
        };
      });

      if (data.invoice.status === 'PAID') {
        scheduleSuccessRedirect();
      }
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : 'Не удалось обновить статус оплаты');
    }
  }, [scheduleSuccessRedirect]);

  const cancelInvoice = useCallback(async () => {
    if (!invoice?.id) {
      return;
    }

    setIsCancelling(true);
    setErrorMessage('');

    try {
      const response = await fetch(`/api/billing/invoices/${invoice.id}`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action: 'cancel' }),
      });

      if (!response.ok) {
        throw new Error(await getResponseErrorTextWithRequestId(response, 'Не удалось отменить оплату'));
      }

      const data = await response.json() as InvoiceStatusResponse;
      setInvoice((current) => {
        if (!current) {
          return current;
        }

        return {
          ...current,
          status: data.invoice.status,
          expiresAt: data.invoice.expiresAt,
          paidAt: data.invoice.paidAt,
        };
      });

      if (data.invoice.status === 'CANCELLED') {
        scheduleCancelRedirect();
      }
    } catch (error) {
      setErrorMessage(error instanceof Error ? error.message : 'Не удалось отменить оплату');
    } finally {
      setIsCancelling(false);
    }
  }, [invoice?.id, scheduleCancelRedirect]);

  useEffect(() => {
    return () => {
      clearCancelRedirect();
    };
  }, [clearCancelRedirect]);

  useEffect(() => {
    redirectedRef.current = false;
    void createInvoice();
  }, [createInvoice, retryToken]);

  useEffect(() => {
    if (!invoice?.expiresAt || invoice.status !== 'PENDING') {
      return;
    }

    const timer = setInterval(() => {
      setNowTs(Date.now());
    }, 30_000);

    return () => clearInterval(timer);
  }, [invoice?.expiresAt, invoice?.status]);

  const invoiceId = invoice?.id;
  const invoiceStatus = invoice?.status;
  const invoiceOpenUrl = useMemo(() => (invoice ? getInvoiceOpenUrl(invoice) : null), [invoice]);
  const invoiceExpiry = useMemo(() => {
    if (!invoice?.expiresAt) {
      return { absolute: '—', relative: null as string | null };
    }

    const expiresAtMs = new Date(invoice.expiresAt).getTime();
    if (Number.isNaN(expiresAtMs)) {
      return { absolute: '—', relative: null as string | null };
    }

    const deltaMs = expiresAtMs - nowTs;
    if (deltaMs <= 0) {
      return { absolute: formatDateTime(invoice.expiresAt), relative: 'счёт истёк' };
    }

    return {
      absolute: formatDateTime(invoice.expiresAt),
      relative: `ещё ${formatRemainingTime(deltaMs)}`,
    };
  }, [invoice?.expiresAt, nowTs]);

  useEffect(() => {
    if (!invoiceId || invoiceStatus !== 'PENDING') {
      return;
    }

    void refreshInvoiceStatus(invoiceId);

    const timer = setInterval(() => {
      void refreshInvoiceStatus(invoiceId);
    }, POLL_INTERVAL_MS);

    return () => clearInterval(timer);
  }, [invoiceId, invoiceStatus, refreshInvoiceStatus]);

  const canRetry = !isCreating && !invoice;

  return (
    <section className="mx-auto w-full max-w-2xl rounded-[1.5rem] border border-white/10 bg-black/40 p-6 text-white shadow-[0_24px_80px_rgba(0,0,0,0.6)] backdrop-blur-xl sm:p-8">
      <header className="mb-6">
        <p className="mb-1 text-xs uppercase tracking-[0.14em] text-gray-500">Оплата тарифа</p>
        <h1 className="text-2xl font-bold tracking-tight text-white">{planMeta.label}</h1>
        <p className="mt-1 text-sm text-gray-400">{getPeriodLabel(interval)}</p>
      </header>

      <div className="grid sm:grid-cols-2 gap-4 mb-6">
        <div className="rounded-xl border border-white/10 bg-white/[0.03] p-4">
          <p className="mb-1 text-xs text-gray-500">Сумма</p>
          <p className="text-xl font-semibold text-white">{amountUsdCents === null ? '-' : formatUsdCents(amountUsdCents)}</p>
        </div>
        <div className="rounded-xl border border-white/10 bg-white/[0.03] p-4">
          <p className="mb-1 text-xs text-gray-500">Статус</p>
          <p className="text-xl font-semibold text-white">
            {invoice
              ? getStatusLabel(invoice.status)
              : (isCreating ? 'Создаём счёт...' : '—')}
          </p>
        </div>
      </div>

      <ApiErrorAlert message={errorMessage} className="mb-4" />

      {isCreating ? (
        <div className="mb-6 flex items-center gap-2 text-sm text-gray-400">
          <span className="h-4 w-4 animate-spin rounded-full border-2 border-violet-400 border-t-transparent" />
          Создаём счёт в CryptoBot...
        </div>
      ) : null}

      {!isCreating && invoice ? (
        <div className="space-y-4">
          <div className="rounded-xl border border-white/10 bg-white/[0.03] p-4">
            <p className="mb-1 text-xs text-gray-500">ID счёта</p>
            <p className="break-all font-mono text-sm text-gray-200">{invoice.id}</p>
          </div>

          <div className="rounded-xl border border-white/10 bg-white/[0.03] p-4">
            <p className="mb-1 text-xs text-gray-500">Действует до</p>
            <p className="text-sm text-gray-200">{invoiceExpiry.absolute}</p>
            {invoiceExpiry.relative ? (
              <p className="mt-1 text-xs text-gray-500">{invoiceExpiry.relative}</p>
            ) : null}
          </div>

          <div className="grid gap-3">
            {invoiceOpenUrl ? (
              <a
                href={invoiceOpenUrl}
                target="_blank"
                rel="noopener noreferrer"
                className="inline-flex h-11 w-full items-center justify-center rounded-xl bg-gradient-to-r from-fuchsia-500 to-violet-600 px-4 text-center text-sm font-semibold text-white transition-colors hover:from-fuchsia-500/90 hover:to-violet-600/90"
              >
                Открыть счёт
              </a>
            ) : null}
          </div>

          {invoice.status === 'PENDING' ? (
            <button
              type="button"
              onClick={cancelInvoice}
              disabled={isCancelling}
              className="w-full rounded-xl border border-red-500/35 bg-red-500/10 px-4 py-2.5 text-sm font-medium text-red-200 transition-colors hover:bg-red-500/20 disabled:cursor-not-allowed disabled:opacity-60"
            >
              {isCancelling ? 'Отменяем счёт...' : 'Отменить счёт'}
            </button>
          ) : null}

          {invoice.status === 'PAID' ? (
            <div className="rounded-xl border border-emerald-500/30 bg-emerald-500/10 p-4 text-sm text-emerald-200">
              Платёж подтверждён. Переводим вас в профиль...
            </div>
          ) : null}

          {invoice.status === 'CANCELLED' ? (
            <div className="rounded-xl border border-white/10 bg-white/[0.03] p-4 text-sm text-gray-400">
              Оплата отменена. Возвращаем вас в профиль через 5 секунд...
            </div>
          ) : null}

        </div>
      ) : null}

      {canRetry ? (
        <button
          type="button"
          className="inline-flex h-11 items-center justify-center rounded-xl bg-gradient-to-r from-fuchsia-500 to-violet-600 px-4 text-sm font-semibold text-white transition-colors hover:from-fuchsia-500/90 hover:to-violet-600/90"
          onClick={() => setRetryToken((value) => value + 1)}
        >
          Повторить
        </button>
      ) : null}
    </section>
  );
}
