/**
 * Pipeline admin dashboard — video list with status, retrigger/revoke,
 * expandable event log with token usage and collapsible JSON viewer.
 */

import { useCallback, useEffect, useState } from "react";
import {
  fetchPipelineVideos,
  fetchPipelineEvents,
  fetchWorkerStatus,
  triggerPipeline,
  revokePipeline,
  type PipelineVideoItem,
  type PipelineEvent,
  type WorkerStatusResponse,
} from "../api/public-client";

// ── Helpers ──────────────────────────────────────────────────────────────────

function formatDate(iso: string | null): string {
  if (!iso) return "—";
  return new Date(iso).toLocaleString(undefined, {
    month: "short",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  });
}

function formatTokens(n: number): string {
  if (n === 0) return "0";
  if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
  if (n >= 1_000) return `${(n / 1_000).toFixed(1)}k`;
  return String(n);
}

function statusBadgeClass(status: string): string {
  switch (status) {
    case "completed":
    case "indexed":
      return "pipeline-badge--success";
    case "processing":
    case "extracted":
    case "classified":
    case "synthesized":
      return "pipeline-badge--active";
    case "failed":
    case "error":
      return "pipeline-badge--error";
    case "pending":
    case "queued":
      return "pipeline-badge--pending";
    default:
      return "";
  }
}

function eventTypeIcon(eventType: string): string {
  switch (eventType) {
    case "start":
      return "▶";
    case "complete":
      return "✓";
    case "error":
      return "✗";
    case "llm_call":
      return "🤖";
    default:
      return "·";
  }
}

// ── Collapsible JSON ─────────────────────────────────────────────────────────

function JsonViewer({ data }: { data: Record<string, unknown> | null }) {
  const [open, setOpen] = useState(false);
  if (!data || Object.keys(data).length === 0) return null;

  return (
    <div className="json-viewer">
      <button
        className="json-viewer__toggle"
        onClick={() => setOpen((v) => !v)}
        aria-expanded={open}
      >
        {open ? "▾ Hide payload" : "▸ Show payload"}
      </button>
      {open && (
        <pre className="json-viewer__content">
          {JSON.stringify(data, null, 2)}
        </pre>
      )}
    </div>
  );
}

// ── Event Log ────────────────────────────────────────────────────────────────

function EventLog({ videoId }: { videoId: string }) {
  const [events, setEvents] = useState<PipelineEvent[]>([]);
  const [total, setTotal] = useState(0);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [offset, setOffset] = useState(0);
  const limit = 50;

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const res = await fetchPipelineEvents(videoId, { offset, limit });
      setEvents(res.items);
      setTotal(res.total);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to load events");
    } finally {
      setLoading(false);
    }
  }, [videoId, offset]);

  useEffect(() => {
    void load();
  }, [load]);

  if (loading) return <div className="loading">Loading events…</div>;
  if (error) return <div className="loading error-text">Error: {error}</div>;
  if (events.length === 0) return <div className="pipeline-events__empty">No events recorded.</div>;

  const hasNext = offset + limit < total;
  const hasPrev = offset > 0;

  return (
    <div className="pipeline-events">
      <div className="pipeline-events__header">
        <span className="pipeline-events__count">{total} event{total !== 1 ? "s" : ""}</span>
        <button className="btn btn--small btn--secondary" onClick={() => void load()}>↻ Refresh</button>
      </div>

      <div className="pipeline-events__list">
        {events.map((evt) => (
          <div key={evt.id} className={`pipeline-event pipeline-event--${evt.event_type}`}>
            <div className="pipeline-event__row">
              <span className="pipeline-event__icon">{eventTypeIcon(evt.event_type)}</span>
              <span className="pipeline-event__stage">{evt.stage}</span>
              <span className={`pipeline-badge pipeline-badge--event-${evt.event_type}`}>
                {evt.event_type}
              </span>
              {evt.model && <span className="pipeline-event__model">{evt.model}</span>}
              {evt.total_tokens != null && evt.total_tokens > 0 && (
                <span className="pipeline-event__tokens" title={`prompt: ${evt.prompt_tokens ?? 0} / completion: ${evt.completion_tokens ?? 0}`}>
                  {formatTokens(evt.total_tokens)} tok
                </span>
              )}
              {evt.duration_ms != null && (
                <span className="pipeline-event__duration">{evt.duration_ms}ms</span>
              )}
              <span className="pipeline-event__time">{formatDate(evt.created_at)}</span>
            </div>
            <JsonViewer data={evt.payload} />
          </div>
        ))}
      </div>

      {(hasPrev || hasNext) && (
        <div className="pipeline-events__pager">
          <button
            className="btn btn--small btn--secondary"
            disabled={!hasPrev}
            onClick={() => setOffset((o) => Math.max(0, o - limit))}
          >
            ← Prev
          </button>
          <span className="pipeline-events__pager-info">
            {offset + 1}–{Math.min(offset + limit, total)} of {total}
          </span>
          <button
            className="btn btn--small btn--secondary"
            disabled={!hasNext}
            onClick={() => setOffset((o) => o + limit)}
          >
            Next →
          </button>
        </div>
      )}
    </div>
  );
}

// ── Worker Status ────────────────────────────────────────────────────────────

function WorkerStatus() {
  const [status, setStatus] = useState<WorkerStatusResponse | null>(null);
  const [error, setError] = useState<string | null>(null);

  const load = useCallback(async () => {
    try {
      setError(null);
      const res = await fetchWorkerStatus();
      setStatus(res);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed");
    }
  }, []);

  useEffect(() => {
    void load();
    const id = setInterval(() => void load(), 15_000);
    return () => clearInterval(id);
  }, [load]);

  if (error) {
    return (
      <div className="worker-status worker-status--error">
        <span className="worker-status__dot worker-status__dot--offline" />
        Worker: error ({error})
      </div>
    );
  }

  if (!status) {
    return (
      <div className="worker-status">
        <span className="worker-status__dot worker-status__dot--unknown" />
        Worker: checking…
      </div>
    );
  }

  return (
    <div className={`worker-status ${status.online ? "worker-status--online" : "worker-status--offline"}`}>
      <span className={`worker-status__dot ${status.online ? "worker-status__dot--online" : "worker-status__dot--offline"}`} />
      <span className="worker-status__label">
        {status.online ? `${status.workers.length} worker${status.workers.length !== 1 ? "s" : ""} online` : "Workers offline"}
      </span>
      {status.workers.map((w) => (
        <span key={w.name} className="worker-status__detail" title={w.name}>
          {w.active_tasks.length > 0
            ? `${w.active_tasks.length} active`
            : "idle"}
          {w.pool_size != null && ` · pool ${w.pool_size}`}
        </span>
      ))}
    </div>
  );
}

// ── Main Page ────────────────────────────────────────────────────────────────

export default function AdminPipeline() {
  const [videos, setVideos] = useState<PipelineVideoItem[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [expandedId, setExpandedId] = useState<string | null>(null);
  const [actionLoading, setActionLoading] = useState<string | null>(null);
  const [actionMessage, setActionMessage] = useState<{ id: string; text: string; ok: boolean } | null>(null);

  const load = useCallback(async () => {
    setLoading(true);
    setError(null);
    try {
      const res = await fetchPipelineVideos();
      setVideos(res.items);
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to load videos");
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    void load();
  }, [load]);

  const handleTrigger = async (videoId: string) => {
    setActionLoading(videoId);
    setActionMessage(null);
    try {
      const res = await triggerPipeline(videoId);
      setActionMessage({ id: videoId, text: `Triggered (${res.status})`, ok: true });
      // Refresh after short delay to let status update
      setTimeout(() => void load(), 2000);
    } catch (err) {
      setActionMessage({
        id: videoId,
        text: err instanceof Error ? err.message : "Trigger failed",
        ok: false,
      });
    } finally {
      setActionLoading(null);
    }
  };

  const handleRevoke = async (videoId: string) => {
    setActionLoading(videoId);
    setActionMessage(null);
    try {
      const res = await revokePipeline(videoId);
      setActionMessage({
        id: videoId,
        text: res.tasks_revoked > 0
          ? `Revoked ${res.tasks_revoked} task${res.tasks_revoked !== 1 ? "s" : ""}`
          : "No active tasks",
        ok: true,
      });
      setTimeout(() => void load(), 2000);
    } catch (err) {
      setActionMessage({
        id: videoId,
        text: err instanceof Error ? err.message : "Revoke failed",
        ok: false,
      });
    } finally {
      setActionLoading(null);
    }
  };

  const toggleExpand = (id: string) => {
    setExpandedId((prev) => (prev === id ? null : id));
  };

  return (
    <div className="admin-pipeline">
      <div className="admin-pipeline__header">
        <div>
          <h2 className="admin-pipeline__title">Pipeline Management</h2>
          <p className="admin-pipeline__subtitle">
            {videos.length} video{videos.length !== 1 ? "s" : ""}
          </p>
        </div>
        <div className="admin-pipeline__header-right">
          <WorkerStatus />
          <button className="btn btn--secondary" onClick={() => void load()} disabled={loading}>
            ↻ Refresh
          </button>
        </div>
      </div>

      {loading ? (
        <div className="loading">Loading videos…</div>
      ) : error ? (
        <div className="loading error-text">Error: {error}</div>
      ) : videos.length === 0 ? (
        <div className="empty-state">No videos in pipeline.</div>
      ) : (
        <div className="admin-pipeline__list">
          {videos.map((video) => (
            <div key={video.id} className="pipeline-video">
              <div
                className="pipeline-video__header"
                onClick={() => toggleExpand(video.id)}
              >
                <div className="pipeline-video__info">
                  <span className="pipeline-video__filename" title={video.filename}>
                    {video.filename}
                  </span>
                  <span className="pipeline-video__creator">{video.creator_name}</span>
                </div>

                <div className="pipeline-video__meta">
                  <span className={`pipeline-badge ${statusBadgeClass(video.processing_status)}`}>
                    {video.processing_status}
                  </span>
                  <span className="pipeline-video__stat" title="Events">
                    {video.event_count} events
                  </span>
                  <span className="pipeline-video__stat" title="Total tokens used">
                    {formatTokens(video.total_tokens_used)} tokens
                  </span>
                  <span className="pipeline-video__time">
                    {formatDate(video.last_event_at)}
                  </span>
                </div>

                <div className="pipeline-video__actions" onClick={(e) => e.stopPropagation()}>
                  <button
                    className="btn btn--small btn--primary"
                    onClick={() => void handleTrigger(video.id)}
                    disabled={actionLoading === video.id}
                    title="Retrigger pipeline"
                  >
                    {actionLoading === video.id ? "…" : "▶ Trigger"}
                  </button>
                  <button
                    className="btn btn--small btn--danger"
                    onClick={() => void handleRevoke(video.id)}
                    disabled={actionLoading === video.id}
                    title="Revoke active tasks"
                  >
                    {actionLoading === video.id ? "…" : "■ Revoke"}
                  </button>
                </div>
              </div>

              {actionMessage?.id === video.id && (
                <div className={`pipeline-video__message ${actionMessage.ok ? "pipeline-video__message--ok" : "pipeline-video__message--err"}`}>
                  {actionMessage.text}
                </div>
              )}

              {expandedId === video.id && (
                <div className="pipeline-video__detail">
                  <div className="pipeline-video__detail-meta">
                    <span>ID: {video.id.slice(0, 8)}…</span>
                    <span>Created: {formatDate(video.created_at)}</span>
                    <span>Updated: {formatDate(video.updated_at)}</span>
                  </div>
                  <EventLog videoId={video.id} />
                </div>
              )}
            </div>
          ))}
        </div>
      )}
    </div>
  );
}
