import { h } from 'preact';
import { useState, useEffect, useCallback } from 'preact/hooks';

// AuditEvent mirrors the JSON returned by GET /api/v1/audit (internal/audit.Event).
interface AuditEvent {
  time: string;
  actor: string;
  actorType: string; // "user" | "system"
  action: string;
  ds?: string;
  signal?: string;
  value?: string;
  detail?: string;
  ip?: string;
  outcome: string; // "ok" | "error"
  error?: string;
}

interface Props { onClose: () => void; }

/** Convert an RFC3339/ISO timestamp to a compact local datetime string. */
function fmtTime(iso: string): string {
  const d = new Date(iso);
  if (isNaN(d.getTime())) return iso;
  const pad = (n: number) => String(n).padStart(2, '0');
  return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}:${pad(d.getSeconds())}`;
}

/** Convert a datetime-local input value (local time) to an RFC3339 string. */
function localToRFC3339(v: string): string {
  if (!v) return '';
  const d = new Date(v);
  return isNaN(d.getTime()) ? '' : d.toISOString();
}

export default function AuditViewer({ onClose }: Props) {
  const [events, setEvents] = useState<AuditEvent[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Filters
  const [user, setUser] = useState('');
  const [action, setAction] = useState('');
  const [signal, setSignal] = useState('');
  const [start, setStart] = useState('');
  const [end, setEnd] = useState('');

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const q = new URLSearchParams();
      if (user.trim()) q.set('user', user.trim());
      if (action) q.set('action', action);
      if (signal.trim()) q.set('signal', signal.trim());
      const s = localToRFC3339(start);
      const e = localToRFC3339(end);
      if (s) q.set('start', s);
      if (e) q.set('end', e);
      const res = await fetch(`/api/v1/audit?${q.toString()}`);
      if (res.status === 403) throw new Error('You are not permitted to view the audit log.');
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const data = await res.json();
      setEvents(Array.isArray(data) ? data : []);
    } catch (err) {
      setError(err instanceof Error ? err.message : String(err));
      setEvents([]);
    } finally {
      setLoading(false);
    }
  }, [user, action, signal, start, end]);

  // Initial load.
  useEffect(() => { load(); }, []); // eslint-disable-line react-hooks/exhaustive-deps

  function resetFilters() {
    setUser(''); setAction(''); setSignal(''); setStart(''); setEnd('');
  }

  return (
    <div class="cl-overlay" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div class="cl-modal audit-modal">
        <header class="cl-header">
          <span class="cl-title">Audit log</span>
          <span class="hint cl-subtitle">Every system-affecting action (signal writes, control-logic and interface changes).</span>
          <div class="cl-header-actions">
            <button class="panel-btn" disabled={loading} onClick={load}>{loading ? 'Loading…' : 'Refresh'}</button>
            <button class="panel-btn" onClick={onClose}>Close</button>
          </div>
        </header>

        <div class="audit-filters">
          <input class="audit-filter" type="text" placeholder="User" value={user}
            onInput={(e) => setUser((e.target as HTMLInputElement).value)} />
          <select class="audit-filter" value={action}
            onChange={(e) => setAction((e.target as HTMLSelectElement).value)}>
            <option value="">All actions</option>
            <option value="signal.write">signal.write</option>
            <option value="interface.create">interface.create</option>
            <option value="interface.update">interface.update</option>
            <option value="interface.delete">interface.delete</option>
            <option value="controllogic.create">controllogic.create</option>
            <option value="controllogic.update">controllogic.update</option>
            <option value="controllogic.delete">controllogic.delete</option>
          </select>
          <input class="audit-filter" type="text" placeholder="Signal contains…" value={signal}
            onInput={(e) => setSignal((e.target as HTMLInputElement).value)} />
          <label class="audit-filter-label">From
            <input class="audit-filter" type="datetime-local" value={start}
              onInput={(e) => setStart((e.target as HTMLInputElement).value)} />
          </label>
          <label class="audit-filter-label">To
            <input class="audit-filter" type="datetime-local" value={end}
              onInput={(e) => setEnd((e.target as HTMLInputElement).value)} />
          </label>
          <button class="panel-btn" disabled={loading} onClick={load}>Apply</button>
          <button class="panel-btn" onClick={resetFilters}>Reset</button>
        </div>

        {error && <div class="cl-error">{error}</div>}

        <div class="audit-body">
          {!error && events.length === 0 && !loading && (
            <div class="hint audit-empty">No matching audit entries.</div>
          )}
          {events.length > 0 && (
            <table class="audit-table">
              <thead>
                <tr>
                  <th>Time</th>
                  <th>Actor</th>
                  <th>Action</th>
                  <th>Source</th>
                  <th>Signal / target</th>
                  <th>Value</th>
                  <th>Detail</th>
                  <th>Client</th>
                  <th>Result</th>
                </tr>
              </thead>
              <tbody>
                {events.map((ev, i) => (
                  <tr key={i} class={ev.outcome === 'error' ? 'audit-row-error' : ''}>
                    <td class="audit-time">{fmtTime(ev.time)}</td>
                    <td>
                      <span class={`audit-actor-tag audit-actor-${ev.actorType}`}>{ev.actorType}</span>
                      {' '}{ev.actor || '—'}
                    </td>
                    <td>{ev.action}</td>
                    <td>{ev.ds || '—'}</td>
                    <td class="audit-signal" title={ev.signal}>{ev.signal || '—'}</td>
                    <td class="audit-value" title={ev.value}>{ev.value ?? '—'}</td>
                    <td class="audit-detail" title={ev.detail}>{ev.detail || '—'}</td>
                    <td>{ev.ip || '—'}</td>
                    <td>
                      {ev.outcome === 'error'
                        ? <span class="audit-result-err" title={ev.error}>error</span>
                        : <span class="audit-result-ok">ok</span>}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </div>
  );
}
