'use client';

import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { JobTypePill } from '@/components/admin/JobTypePill';
import { jobTypeLabel, ALL_JOB_TYPES } from '@/lib/gsc-job-type-labels';
import { ADMIN_LIST_MAX_LIMIT } from '@/lib/admin-constants';
import styles from './FailuresTable.module.css';

interface FailureRow {
  id: string;
  type: string;
  dealerId: string;
  dealerName: string | null;
  dealerEmail: string | null;
  domain: string | null;
  attempts: number;
  lastError: string | null;
  errorStatus: number | null;
  errorShort: string | null;
  updatedAt: string;
}

interface Props {
  onSelectDealer: (dealerId: string) => void;
  pageSize?: number;
}

export function FailuresTable({ onSelectDealer, pageSize = 25 }: Props) {
  // null = loading in progress; [] = loaded with no results
  const [rows, setRows] = useState<FailureRow[] | null>(null);
  const [total, setTotal] = useState(0);
  const [error, setError] = useState<string | null>(null);
  const [q, setQ] = useState('');
  const [type, setType] = useState<string | null>(null);
  const [grouped, setGrouped] = useState(true);
  const [page, setPage] = useState(0);
  const fetchCountRef = useRef(0);

  useEffect(() => {
    // Loading-state reset must be urgent (not deferred via startTransition)
    // so the spinner shows immediately on every re-query. The lint rule
    // discourages setState inside effects because of cascading renders,
    // but here it's intentional: the effect's dep array narrowly bounds
    // re-runs to q/type/page/pageSize changes, and the cascade is what
    // we want — the next render shows "Loading…".
    // eslint-disable-next-line react-hooks/set-state-in-effect
    setRows(null);
    // Server pagination is grouping-blind, so when grouped=true we fetch up to
    // the API cap (200) in a single page and disable pagination controls.
    // Otherwise the same dealer's failures can interleave across page
    // boundaries, making the "Showing N of M" labels lie.
    const effectiveLimit = grouped ? ADMIN_LIST_MAX_LIMIT : pageSize;
    const effectiveOffset = grouped ? 0 : page * pageSize;
    const params = new URLSearchParams({
      status: 'failed',
      limit: String(effectiveLimit),
      offset: String(effectiveOffset),
      sinceHours: '24',
    });
    if (q) params.set('q', q);
    if (type) params.set('type', type);
    const fetchId = ++fetchCountRef.current;
    fetch(`/api/admin/gsc/jobs?${params.toString()}`)
      .then((r) => {
        if (!r.ok) throw new Error(`HTTP ${r.status}`);
        return r.json();
      })
      .then((data) => {
        if (fetchId !== fetchCountRef.current) return;
        setRows(data.jobs);
        setTotal(data.total);
        setError(null);
      })
      .catch((e) => {
        if (fetchId !== fetchCountRef.current) return;
        setError(e instanceof Error ? e.message : String(e));
      });
  }, [q, type, page, pageSize, grouped]);

  const grouping = useMemo(() => {
    if (!grouped || !rows) return null;
    const groups = new Map<string, FailureRow[]>();
    for (const r of rows) {
      const arr = groups.get(r.dealerId) ?? [];
      arr.push(r);
      groups.set(r.dealerId, arr);
    }
    return groups;
  }, [rows, grouped]);

  const renderRow = useCallback(
    (r: FailureRow, hideName = false) => (
      <tr key={r.id}>
        <td className={styles.clickableCell} onClick={() => onSelectDealer(r.dealerId)}>
          {!hideName && <div className={styles.dealerName}>{r.dealerName ?? r.dealerId}</div>}
          {r.dealerEmail && <div className={styles.dealerEmail}>{r.dealerEmail}</div>}
        </td>
        <td>
          {r.domain ? (
            <a
              className={styles.domainLink}
              href={`https://${r.domain}`}
              target="_blank"
              rel="noopener noreferrer"
            >
              {r.domain}
            </a>
          ) : (
            <span>—</span>
          )}
        </td>
        <td>
          <JobTypePill type={r.type} />
        </td>
        <td>
          {r.errorStatus != null && <span className={styles.errPill}>{r.errorStatus}</span>}
          {r.errorShort ?? r.lastError ?? '—'}
        </td>
        <td>{r.attempts}</td>
        <td>{new Date(r.updatedAt).toLocaleString()}</td>
      </tr>
    ),
    [onSelectDealer]
  );

  const displayRows = rows ?? [];

  return (
    <div>
      <div className={styles.toolbar}>
        <input
          className={styles.search}
          placeholder="Search dealer name, email, domain…"
          value={q}
          onChange={(e) => {
            setQ(e.target.value);
            setPage(0);
          }}
        />
        <button
          type="button"
          className={`${styles.chip} ${type === null ? styles.chipActive : ''}`}
          onClick={() => {
            setType(null);
            setPage(0);
          }}
        >
          all types
        </button>
        {ALL_JOB_TYPES.map((t) => (
          <button
            key={t}
            type="button"
            className={`${styles.chip} ${type === t ? styles.chipActive : ''}`}
            onClick={() => {
              setType(t);
              setPage(0);
            }}
          >
            {jobTypeLabel(t)}
          </button>
        ))}
        <label className={styles.toggle}>
          <input
            type="checkbox"
            checked={grouped}
            onChange={(e) => {
              setGrouped(e.target.checked);
              // Reset to page 0 in both directions: grouped→flat shouldn't
              // leave a stale offset that points past the flat result set.
              setPage(0);
            }}
          />
          Group by dealer
        </label>
      </div>

      {error && (
        <div className={styles.errorBanner} role="alert">
          <p>Failed to load: {error}</p>
        </div>
      )}
      {rows === null && <p className={styles.loadingMsg}>Loading…</p>}
      {rows !== null && rows.length === 0 && !error && (
        <p className={styles.emptyState}>No failures in the last 24 hours.</p>
      )}

      <table className={styles.table}>
        <thead>
          <tr>
            <th>Dealer</th>
            <th>Domain</th>
            <th>Type</th>
            <th>Error</th>
            <th>Attempts</th>
            <th>When</th>
          </tr>
        </thead>
        <tbody>
          {grouping
            ? Array.from(grouping.entries()).flatMap(([dealerId, group]) => [
                <tr key={`g-${dealerId}`} className={styles.groupRow}>
                  <td
                    colSpan={6}
                    className={styles.clickableCell}
                    onClick={() => onSelectDealer(dealerId)}
                  >
                    {'▾ '}
                    <span className={styles.dealerName}>{group[0].dealerName ?? dealerId}</span>
                    {' · '}
                    {group.length} on this page
                  </td>
                </tr>,
                ...group.map((r) => renderRow(r, true)),
              ])
            : displayRows.map((r) => renderRow(r))}
        </tbody>
      </table>

      <div className={styles.pagination}>
        {grouped ? (
          <span>
            Showing {displayRows.length} of {total}
            {total > displayRows.length && ' (capped — disable Group by dealer to paginate)'}
          </span>
        ) : (
          <>
            <span>
              Showing {displayRows.length ? page * pageSize + 1 : 0}–
              {page * pageSize + displayRows.length} of {total}
            </span>
            <span>
              <button
                type="button"
                className={styles.pageBtn}
                disabled={page === 0}
                onClick={() => setPage((p) => Math.max(0, p - 1))}
              >
                ←
              </button>{' '}
              Page {page + 1} of {Math.max(1, Math.ceil(total / pageSize))}{' '}
              <button
                type="button"
                className={styles.pageBtn}
                disabled={(page + 1) * pageSize >= total}
                onClick={() => setPage((p) => p + 1)}
              >
                →
              </button>
            </span>
          </>
        )}
      </div>
    </div>
  );
}
