import React, { useEffect, useState } from 'react';
import type { IconType } from 'react-icons';
import {
  FaBarcode,
  FaBookOpen,
  FaChevronLeft,
  FaChevronRight,
  FaCoins,
  FaDownload,
  FaMagic,
  FaRegFileAlt,
  FaRegImage,
  FaRegNewspaper,
  FaSatelliteDish,
  FaShieldAlt,
  FaSpinner,
  FaTimes,
} from 'react-icons/fa';

import {
  CREDIT_HISTORY_PAGE_SIZE,
  EMPTY_CREDIT_HISTORY,
  type ICreditTransaction,
  type ICreditTransactionsResponse,
} from '../../service/credits/credits.interface';
import {
  fetchCreditTransactionsExport,
  getCreditTransactions,
} from '../../service/credits/credits.service';

/** Joins truthy class fragments (this app has no `cn` helper). */
function cx(...parts: Array<string | false | null | undefined>): string {
  return parts.filter(Boolean).join(' ');
}

interface ReasonMeta {
  label: string;
  icon: IconType;
}

const REASON_META: Record<string, ReasonMeta> = {
  CONTENT_GEN: { label: 'Content generation', icon: FaRegFileAlt },
  PRODUCT_SCAN: { label: 'Product scan', icon: FaBarcode },
  INLINE_FIX: { label: 'Inline fix', icon: FaMagic },
  GAP_VERIFICATION: { label: 'Gap verification', icon: FaShieldAlt },
  KB_DOC: { label: 'Knowledge base', icon: FaBookOpen },
  ARTICLE_GEN: { label: 'Content generation', icon: FaRegNewspaper },
  ARTICLE_IMAGE: { label: 'Content image', icon: FaRegImage },
  VISIBILITY_SCAN: { label: 'Visibility scan', icon: FaSatelliteDish },
};

function reasonMeta(reason: string): ReasonMeta {
  return (
    REASON_META[reason] ?? {
      label: reason
        .toLowerCase()
        .split('_')
        .map(word => word.charAt(0).toUpperCase() + word.slice(1))
        .join(' '),
      icon: FaCoins,
    }
  );
}

function formatTimestamp(iso: string): string {
  const date = new Date(iso);
  if (Number.isNaN(date.getTime())) return '—';

  return date.toLocaleString(undefined, {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
    hour: '2-digit',
    minute: '2-digit',
  });
}

interface CreditHistoryTableProps {
  token: string;
  clientId?: string | null;
}

/**
 * Self-contained, paginated table of credit consumption/grants (newest first)
 * with a date-range filter and an xlsx export. Fetches client-side from the
 * credits service and manages its own pagination/filter state.
 *
 * @param {CreditHistoryTableProps} props - Recomaze auth.
 * @return {React.ReactElement} The credit-history table.
 */
export function CreditHistoryTable({
  token,
  clientId,
}: CreditHistoryTableProps) {
  const [data, setData] =
    useState<ICreditTransactionsResponse>(EMPTY_CREDIT_HISTORY);
  const [page, setPage] = useState(1);
  const [startDate, setStartDate] = useState('');
  const [endDate, setEndDate] = useState('');
  const [loading, setLoading] = useState(true);
  const [exporting, setExporting] = useState(false);
  const [exportError, setExportError] = useState<string | null>(null);

  useEffect(() => {
    if (!token) return;
    let cancelled = false;
    setLoading(true);
    getCreditTransactions(
      token,
      clientId,
      page,
      CREDIT_HISTORY_PAGE_SIZE,
      startDate || undefined,
      endDate || undefined
    )
      .then(response => {
        if (!cancelled) setData(response);
      })
      .finally(() => {
        if (!cancelled) setLoading(false);
      });

    return () => {
      cancelled = true;
    };
  }, [token, clientId, page, startDate, endDate]);

  const transactions = data.transactions;
  const totalPages = data.total_pages;
  const total = data.total;
  const hasPrev = page > 1;
  const hasNext = page < totalPages;
  const hasFilter = Boolean(startDate || endDate);

  const handleDateChange = (next: { start?: string; end?: string }) => {
    if (next.start !== undefined) setStartDate(next.start);
    if (next.end !== undefined) setEndDate(next.end);
    setPage(1);
  };

  const handleExport = async () => {
    if (!token) return;
    setExporting(true);
    setExportError(null);
    try {
      const { blob, filename } = await fetchCreditTransactionsExport(
        token,
        clientId,
        startDate || undefined,
        endDate || undefined
      );
      const objectUrl = URL.createObjectURL(blob);
      const anchor = document.createElement('a');
      anchor.href = objectUrl;
      anchor.download = filename;
      document.body.appendChild(anchor);
      anchor.click();
      anchor.remove();
      URL.revokeObjectURL(objectUrl);
    } catch {
      console.warn('[Credits] export failed');
      setExportError('Could not export credit history. Please try again.');
    } finally {
      setExporting(false);
    }
  };

  return (
    <section
      id="credit-history"
      className="scroll-mt-6 overflow-hidden rounded-2xl border border-gray-200 bg-white shadow-sm"
    >
      <header className="flex flex-wrap items-center justify-between gap-3 border-b border-gray-200 bg-gray-50 px-6 py-4">
        <div className="flex items-center gap-2">
          <FaCoins className="h-4 w-4 text-gray-400" />
          <h3 className="text-sm font-semibold text-gray-900">
            Credit history
          </h3>
          <span className="text-xs text-gray-500">
            {total.toLocaleString()} transaction{total === 1 ? '' : 's'}
          </span>
        </div>

        <div className="flex flex-wrap items-center gap-2">
          <label className="flex items-center gap-1.5 text-xs text-gray-500">
            From
            <input
              type="date"
              value={startDate}
              max={endDate || undefined}
              onChange={event =>
                handleDateChange({ start: event.target.value })
              }
              aria-label="Filter from date"
              className="rounded-lg border border-gray-200 px-2 py-1.5 text-xs text-gray-900 focus:outline-none focus:ring-2 focus:ring-[#B7007C]/20"
            />
          </label>
          <label className="flex items-center gap-1.5 text-xs text-gray-500">
            To
            <input
              type="date"
              value={endDate}
              min={startDate || undefined}
              onChange={event => handleDateChange({ end: event.target.value })}
              aria-label="Filter to date"
              className="rounded-lg border border-gray-200 px-2 py-1.5 text-xs text-gray-900 focus:outline-none focus:ring-2 focus:ring-[#B7007C]/20"
            />
          </label>
          {hasFilter && (
            <button
              type="button"
              onClick={() => {
                setStartDate('');
                setEndDate('');
                setPage(1);
              }}
              className="inline-flex h-8 items-center gap-1 rounded-md px-2 text-xs text-gray-500 transition-colors hover:bg-gray-100 hover:text-gray-700"
            >
              <FaTimes className="h-3 w-3" />
              Clear
            </button>
          )}
          <button
            type="button"
            onClick={handleExport}
            disabled={exporting}
            className="inline-flex h-8 items-center gap-1.5 rounded-md border border-gray-200 bg-white px-3 text-xs font-medium text-gray-700 transition-colors hover:border-[#B7007C]/30 hover:text-[#B7007C] disabled:cursor-not-allowed disabled:opacity-60"
          >
            {exporting ? (
              <FaSpinner className="h-3.5 w-3.5 animate-spin" />
            ) : (
              <FaDownload className="h-3.5 w-3.5" />
            )}
            Export
          </button>
        </div>
      </header>

      {exportError && (
        <div className="flex items-center justify-between gap-3 border-b border-red-100 bg-red-50 px-6 py-2 text-xs text-red-600">
          <span>{exportError}</span>
          <button
            type="button"
            onClick={() => setExportError(null)}
            aria-label="Dismiss error"
            className="shrink-0 text-red-400 transition-colors hover:text-red-600"
          >
            <FaTimes className="h-3 w-3" />
          </button>
        </div>
      )}

      {loading ? (
        <div className="space-y-2 p-6">
          {Array.from({ length: 5 }).map((_, index) => (
            <div
              key={index}
              className="h-9 animate-pulse rounded-md bg-gray-50"
            />
          ))}
        </div>
      ) : transactions.length === 0 ? (
        <div className="flex flex-col items-center justify-center gap-2 px-6 py-12 text-center">
          <span className="flex h-10 w-10 items-center justify-center rounded-full bg-gray-100">
            <FaCoins className="h-5 w-5 text-gray-400" />
          </span>
          <p className="text-sm font-medium text-gray-900">
            {hasFilter
              ? 'No transactions in this range'
              : 'No credit usage yet'}
          </p>
          <p className="max-w-xs text-xs text-gray-500">
            {hasFilter
              ? 'Try widening the date range or clearing the filter.'
              : 'Credits you spend on content and scans will show up here.'}
          </p>
        </div>
      ) : (
        <div className="overflow-x-auto">
          <table className="w-full min-w-[40rem] text-sm">
            <thead>
              <tr className="border-b border-gray-200 text-left text-xs font-medium uppercase tracking-wide text-gray-500">
                <th className="px-6 py-3">When</th>
                <th className="px-6 py-3">Description</th>
                <th className="px-6 py-3">Type</th>
                <th className="px-6 py-3 text-right">Credits</th>
                <th className="px-6 py-3 text-right">Balance</th>
              </tr>
            </thead>
            <tbody className="divide-y divide-gray-100">
              {transactions.map((tx: ICreditTransaction) => {
                const meta = reasonMeta(tx.reason);
                const Icon = meta.icon;
                const isSpend = tx.amount < 0;
                const magnitude = Math.abs(tx.amount).toLocaleString();

                return (
                  <tr
                    key={tx.id}
                    className="transition-colors hover:bg-gray-50"
                  >
                    <td className="whitespace-nowrap px-6 py-3 text-gray-500">
                      {formatTimestamp(tx.created_at)}
                    </td>
                    <td className="max-w-md px-6 py-3 text-gray-900">
                      {tx.note ?? meta.label}
                    </td>
                    <td className="px-6 py-3">
                      <span className="inline-flex items-center gap-1 rounded-full border border-gray-200 bg-white px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-gray-600">
                        <Icon className="h-3 w-3" />
                        {meta.label}
                      </span>
                    </td>
                    <td
                      className={cx(
                        'whitespace-nowrap px-6 py-3 text-right font-medium',
                        isSpend ? 'text-red-600' : 'text-emerald-600'
                      )}
                    >
                      {isSpend ? `-${magnitude}` : `+${magnitude}`}
                    </td>
                    <td className="whitespace-nowrap px-6 py-3 text-right font-medium text-gray-900">
                      {tx.balance_after.toLocaleString()}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      {totalPages > 1 && (
        <footer className="flex items-center justify-between gap-3 border-t border-gray-200 px-6 py-3">
          <span className="text-xs text-gray-500">
            Page {page} of {totalPages}
          </span>
          <div className="flex items-center gap-2">
            <PagerButton
              disabled={!hasPrev}
              onClick={() => setPage(p => Math.max(1, p - 1))}
            >
              <FaChevronLeft className="h-3 w-3" />
              Previous
            </PagerButton>
            <PagerButton
              disabled={!hasNext}
              onClick={() => setPage(p => p + 1)}
            >
              Next
              <FaChevronRight className="h-3 w-3" />
            </PagerButton>
          </div>
        </footer>
      )}
    </section>
  );
}

function PagerButton({
  disabled,
  onClick,
  children,
}: {
  disabled: boolean;
  onClick: () => void;
  children: React.ReactNode;
}) {
  return (
    <button
      type="button"
      disabled={disabled}
      onClick={onClick}
      className={cx(
        'inline-flex h-8 items-center gap-1 rounded-md border border-gray-200 px-3 text-xs font-medium transition-colors',
        disabled
          ? 'cursor-not-allowed text-gray-300'
          : 'text-gray-700 hover:bg-gray-50 hover:text-[#B7007C]'
      )}
    >
      {children}
    </button>
  );
}
