import { useEffect, useMemo, useRef, useState } from "react";
import { apiRequest } from "@/lib/queryClient";

type StrategyEvent = {
  seq?: number;
  ts?: string;
  timestamp?: string;
  level?: string;
  category?: string;
  event?: string;
  message?: string;
  run_id?: string;
  meta?: Record<string, unknown>;
};

type StrategyRun = {
  runId: string;
  events: StrategyEvent[];
};

type StrategySummary = {
  run_id?: string | null;
  status?: string | null;
  tone?: "neutral" | "warning" | "error" | "success";
  message?: string | null;
  event?: string | null;
  ts?: string | null;
};

type StrategyTimelineProps = {
  compact?: boolean;
};

function parseTimestamp(value?: string | null) {
  if (!value) return null;
  const parsed = new Date(value);
  return Number.isNaN(parsed.getTime()) ? null : parsed;
}

function normalizeLog(log: unknown): StrategyEvent {
  if (typeof log === "string") {
    try {
      const parsed = JSON.parse(log);
      if (parsed && typeof parsed === "object") {
        return parsed as StrategyEvent;
      }
    } catch {
      return { message: log };
    }
    return { message: log };
  }
  if (log && typeof log === "object") {
    return log as StrategyEvent;
  }
  return { message: "Unknown log entry" };
}

function formatTimestamp(value?: string | null) {
  if (!value) return "Unknown time";
  const parsed = parseTimestamp(value);
  if (!parsed) return value;
  return parsed.toLocaleString();
}

function getTimestampMs(value?: string | null) {
  return parseTimestamp(value)?.getTime() ?? 0;
}

function getRunId(entry: StrategyEvent) {
  return entry.run_id ?? "unknown";
}

function getSeq(entry: StrategyEvent) {
  return typeof entry.seq === "number" ? entry.seq : 0;
}

function getBadge(entry: StrategyEvent) {
  const eventName = (entry.event ?? "UNKNOWN").toUpperCase();
  const meta = entry.meta ?? {};

  if (eventName === "STRATEGY_STARTED") {
    return { label: "START", className: "border-blue-500/40 bg-blue-500/20 text-blue-200" };
  }

  if (eventName === "STRATEGY_STOPPED") {
    return { label: "STOP", className: "border-slate-400/40 bg-slate-400/20 text-slate-200" };
  }

  if (eventName === "STRATEGY_RESUMED") {
    return { label: "RESUME", className: "border-cyan-400/40 bg-cyan-400/20 text-cyan-200" };
  }

  if (eventName === "ORDER_PLACED") {
    const side = typeof meta.side === "string" ? meta.side.toUpperCase() : "";
    if (side === "BUY") {
      return { label: "BUY", className: "border-emerald-400/40 bg-emerald-400/20 text-emerald-200" };
    }
    if (side === "SELL") {
      return { label: "SELL", className: "border-red-400/40 bg-red-400/20 text-red-200" };
    }
    return { label: "ORDER", className: "border-emerald-400/40 bg-emerald-400/20 text-emerald-200" };
  }

  if (eventName === "ERROR") {
    return { label: "ERROR", className: "border-red-400/50 bg-red-500/20 text-red-200" };
  }

  if (eventName === "MARKET_CLOSED") {
    return { label: "MARKET", className: "border-amber-400/40 bg-amber-400/20 text-amber-200" };
  }

  return { label: eventName, className: "border-white/20 bg-white/10 text-white/70" };
}

function getRunStartTime(events: StrategyEvent[]) {
  const startEvent = events.find((entry) => entry.event === "STRATEGY_STARTED") ?? events[0];
  return startEvent?.ts ?? startEvent?.timestamp;
}

function isRunActive(events: StrategyEvent[]) {
  if (events.length === 0) return false;
  const lastEvent = events[events.length - 1];
  return lastEvent.event !== "STRATEGY_STOPPED";
}

function getStopReason(events: StrategyEvent[]) {
  const stopEvent = [...events].reverse().find((entry) => entry.event === "STRATEGY_STOPPED");
  const reason = stopEvent?.meta?.reason;
  return typeof reason === "string" ? reason : null;
}

function CompactStrategySummary() {
  const [summary, setSummary] = useState<StrategySummary | null>(null);

  useEffect(() => {
    let cancelled = false;

    const fetchSummary = async () => {
      try {
        const res = await apiRequest("GET", "/strategy/summary");
        const data = (await res.json()) as StrategySummary;
        if (!cancelled) {
          setSummary(data);
        }
      } catch {
        if (!cancelled) {
          setSummary({
            tone: "error",
            message: "Could not load strategy status.",
          });
        }
      }
    };

    fetchSummary();
    const id = window.setInterval(fetchSummary, 5000);
    return () => {
      cancelled = true;
      window.clearInterval(id);
    };
  }, []);

  const tone = summary?.tone ?? "neutral";
  const message = summary?.message || "No active strategy.";
  const className =
    tone === "error"
      ? "border-red-500/40 bg-red-500/10 text-red-300"
      : tone === "warning"
        ? "border-amber-400/40 bg-amber-400/10 text-amber-200"
        : tone === "success"
          ? "border-emerald-500/40 bg-emerald-500/10 text-emerald-300"
          : "border-border/60 bg-background/40 text-muted-foreground";

  return (
    <div className={`rounded-lg border px-4 py-3 text-sm ${className}`}>
      <div className="flex flex-col gap-1">
        <span>{message}</span>
      </div>
    </div>
  );
}

function VerboseStrategyTimeline() {
  const [logs, setLogs] = useState<StrategyEvent[]>([]);
  const latestSeqRef = useRef(0);

  useEffect(() => {
    const fetchLogs = async () => {
      try {
        const res = await apiRequest("GET", `/logs?since_seq=${latestSeqRef.current}`);
        const data = await res.json();
        const events = Array.isArray(data?.events) ? data.events : [];
        const normalized = events.map(normalizeLog);

        setLogs((prev) => {
          const seenSeq = new Set(
            prev.map((entry) => entry.seq).filter((seq) => typeof seq === "number"),
          );
          const next = normalized.filter(
            (entry: StrategyEvent) => typeof entry.seq !== "number" || !seenSeq.has(entry.seq),
          );
          return [...prev, ...next];
        });

        if (typeof data?.latest_seq === "number") {
          latestSeqRef.current = data.latest_seq;
        } else {
          const lastSeq = normalized.reduce(
            (max: number, entry: StrategyEvent) => Math.max(max, entry.seq ?? 0),
            latestSeqRef.current,
          );
          latestSeqRef.current = lastSeq;
        }
      } catch {
        return;
      }
    };

    fetchLogs();
    const id = setInterval(fetchLogs, 5000);
    return () => clearInterval(id);
  }, []);

  const groupedRuns = useMemo<StrategyRun[]>(() => {
    const grouped = new Map<string, StrategyEvent[]>();
    for (const entry of logs) {
      const runId = getRunId(entry);
      const events = grouped.get(runId) ?? [];
      events.push(entry);
      grouped.set(runId, events);
    }

    const groups = Array.from(grouped.entries()).map(([runId, events]) => ({
      runId,
      events: [...events].sort((a, b) => {
        const seqCompare = getSeq(a) - getSeq(b);
        if (seqCompare !== 0) return seqCompare;
        return getTimestampMs(a.ts ?? a.timestamp) - getTimestampMs(b.ts ?? b.timestamp);
      }),
    }));

    groups.sort((a, b) => {
      const aLast = a.events[a.events.length - 1];
      const bLast = b.events[b.events.length - 1];
      const seqCompare = getSeq(bLast) - getSeq(aLast);
      if (seqCompare !== 0) return seqCompare;
      const timeCompare =
        getTimestampMs(bLast.ts ?? bLast.timestamp) - getTimestampMs(aLast.ts ?? aLast.timestamp);
      if (timeCompare !== 0) return timeCompare;
      return b.runId.localeCompare(a.runId);
    });

    return groups;
  }, [logs]);

  return (
    <div className="bg-black rounded-lg p-4 text-sm text-green-400 h-64 overflow-auto">
      <div className="font-bold mb-2">Strategy Timeline</div>
      {groupedRuns.length === 0 ? (
        <div className="text-xs text-green-300/70">No events yet.</div>
      ) : (
        groupedRuns.map((run) => {
          const active = isRunActive(run.events);
          const startTime = getRunStartTime(run.events);
          const reason = getStopReason(run.events);
          const lastEvent = run.events[run.events.length - 1];
          const lastBadge = getBadge(lastEvent);
          return (
            <div
              key={run.runId}
              className={`mb-4 rounded-lg border p-3 ${
                active ? "border-emerald-500/40 bg-emerald-500/5" : "border-white/10 bg-white/5"
              }`}
            >
              <div className="flex items-start justify-between gap-3">
                <div>
                  <div className="text-sm font-semibold text-white/90">
                    Run started at {formatTimestamp(startTime)}
                  </div>
                  <div className="text-xs text-green-300/70">Run ID: {run.runId}</div>
                </div>
                <div
                  className={`rounded-full border px-2 py-0.5 text-[11px] font-semibold uppercase tracking-wide ${
                    active
                      ? "border-emerald-400/50 bg-emerald-400/20 text-emerald-200"
                      : "border-slate-400/50 bg-slate-400/20 text-slate-200"
                  }`}
                >
                  {active ? "Active" : "Stopped"}
                </div>
              </div>
              <div className="mt-2 flex items-center gap-2 text-xs text-green-300/80">
                <span
                  className={`inline-flex items-center rounded-full border px-2 py-0.5 text-[11px] font-semibold ${lastBadge.className}`}
                >
                  {lastBadge.label}
                </span>
                <span>
                  Last event: {lastEvent.event ?? "UNKNOWN"} at{" "}
                  {formatTimestamp(lastEvent.ts ?? lastEvent.timestamp)}
                </span>
              </div>
              {reason ? (
                <div className="mt-1 text-xs text-green-300/80">Reason: {reason}</div>
              ) : null}
              <div className="mt-3 space-y-3">
                {run.events.map((entry: StrategyEvent, index: number) => {
                  const badge = getBadge(entry);
                  const timestamp = entry.ts ?? entry.timestamp;
                  const message = entry.message ?? entry.event ?? "Unknown event";
                  const meta = entry.meta ?? {};
                  const metaKeys = Object.keys(meta);
                  return (
                    <div key={entry.seq ?? `${run.runId}-${index}`} className="flex items-start gap-3">
                      <span
                        className={`inline-flex items-center rounded-full border px-2 py-0.5 text-[11px] font-semibold ${badge.className}`}
                      >
                        {badge.label}
                      </span>
                      <div className="flex-1">
                        <div className="text-xs text-green-300/80">
                          {formatTimestamp(timestamp)} - {entry.event ?? "UNKNOWN"}
                        </div>
                        {message && message !== entry.event ? (
                          <div className="text-sm text-green-200">{message}</div>
                        ) : null}
                        {typeof meta.reason === "string" ? (
                          <div className="text-xs text-green-300/80">Reason: {meta.reason}</div>
                        ) : null}
                        {metaKeys.length > 0 ? (
                          <details className="mt-1">
                            <summary className="cursor-pointer text-xs text-green-300/70">
                              Details
                            </summary>
                            <pre className="whitespace-pre-wrap text-xs text-green-200/80">
                              {JSON.stringify(meta, null, 2)}
                            </pre>
                          </details>
                        ) : null}
                      </div>
                    </div>
                  );
                })}
              </div>
            </div>
          );
        })
      )}
    </div>
  );
}

export default function StrategyTimeline({ compact = false }: StrategyTimelineProps) {
  if (compact) {
    return <CompactStrategySummary />;
  }
  return <VerboseStrategyTimeline />;
}
