"use client";

import {
  AlertCircle,
  CheckCircle2,
  Clock,
  Copy,
  Loader2,
  Play,
  RefreshCw,
  ScrollText,
  XCircle,
} from "lucide-react";
import { useCallback, useEffect, useMemo, useState } from "react";
import { Button } from "@/components/ui/button";
import { Card } from "@/components/ui/card";
import { cn } from "@/lib/utils";
import { parseProjectTimezone } from "@/lib/scheduling/plan-times";
import type { AutoPostMonitorSnapshot } from "@/types/auto-post-monitor";

interface AutoPostMonitorProps {
  projectId: string | undefined;
  className?: string;
}

type LogPanel = "scheduler" | "publish" | null;

function toneClasses(tone: "ok" | "warn" | "error" | "muted") {
  switch (tone) {
    case "ok":
      return "text-green-700";
    case "warn":
      return "text-amber-700";
    case "error":
      return "text-red-700";
    default:
      return "text-gray-500";
  }
}

function humanizeMonitorBlocker(step: string): string {
  const map: Record<string, string> = {
    scheduler_config: "CRON_SECRET not set on server",
    project_active: "Project is paused",
    schedule_saved: "Smart Schedule not saved",
    smart_timing_enabled: "Smart Random Timing is disabled",
    providers_validated: "No publish-ready connected accounts",
    proposal_queued: "No post queued — enable Loop Post Sequence (auto-generate + direct publish)",
    eligibility_score: "Engagement score below 80 — optional rule (turn off in Automation)",
  };
  return map[step] ?? step.replace(/_/g, " ");
}

function schedulerDot(status: AutoPostMonitorSnapshot["scheduler"]["status"]) {
  switch (status) {
    case "running":
    case "tick_in_progress":
      return "bg-green-500";
    case "stopped":
      return "bg-amber-500";
    default:
      return "bg-gray-400";
  }
}

function formatCountdown(ms: number): string {
  if (ms <= 0) return "now";
  const totalSec = Math.ceil(ms / 1000);
  const h = Math.floor(totalSec / 3600);
  const m = Math.floor((totalSec % 3600) / 60);
  const s = totalSec % 60;
  if (h > 0) return `${h}h ${m}m ${s}s`;
  if (m > 0) return `${m}m ${s}s`;
  return `${s}s`;
}

function formatMonitorTimestamp(iso: string, rawTimeZone?: string): string {
  try {
    const date = new Date(iso);
    if (Number.isNaN(date.getTime())) return iso;
    if (rawTimeZone) {
      const tz = parseProjectTimezone(rawTimeZone);
      return new Intl.DateTimeFormat("en-US", {
        timeZone: tz,
        hour: "numeric",
        minute: "2-digit",
        hour12: true,
      }).format(date);
    }
    return new Intl.DateTimeFormat("en-GB", {
      day: "2-digit",
      month: "short",
      year: "numeric",
      hour: "2-digit",
      minute: "2-digit",
      timeZone: "UTC",
      hour12: false,
    })
      .format(date)
      .replace(",", "");
  } catch {
    return iso;
  }
}

function normalizeSnapshot(raw: AutoPostMonitorSnapshot): AutoPostMonitorSnapshot {
  return {
    ...raw,
    platforms: Array.isArray(raw.platforms) ? raw.platforms : [],
    schedule: {
      ...raw.schedule,
      plannedSlots: Array.isArray(raw.schedule?.plannedSlots) ? raw.schedule.plannedSlots : [],
      activeSlotsNow: Array.isArray(raw.schedule?.activeSlotsNow)
        ? raw.schedule.activeSlotsNow
        : [],
      windowMinutes: raw.schedule?.windowMinutes ?? 30,
      statusLabel: raw.schedule?.statusLabel ?? "Unknown",
      status: raw.schedule?.status ?? "waiting",
      nextSlot: raw.schedule?.nextSlot ?? null,
    },
    timezone: {
      ...raw.timezone,
      raw: raw.timezone?.raw ?? "UTC",
      iana: raw.timezone?.iana ?? parseProjectTimezone(raw.timezone?.raw ?? "UTC"),
      label: raw.timezone?.label ?? "UTC",
      currentTimeLocal: raw.timezone?.currentTimeLocal ?? "—",
      currentDateLocal: raw.timezone?.currentDateLocal ?? "",
    },
    scheduler: {
      ...raw.scheduler,
      status: raw.scheduler?.status ?? "disabled",
      statusLabel: raw.scheduler?.statusLabel ?? "Unknown",
    },
  };
}

function PlatformRow({
  label,
  statusLabel,
  tone,
}: {
  label: string;
  statusLabel: string;
  tone: "ok" | "warn" | "error" | "muted";
}) {
  const Icon =
    tone === "ok" ? CheckCircle2 : tone === "error" ? XCircle : AlertCircle;

  return (
    <li className="flex items-center gap-2 text-sm">
      <Icon className={cn("h-4 w-4 shrink-0", toneClasses(tone))} />
      <span className="font-medium text-gray-900">{label}</span>
      <span className={cn("text-xs", toneClasses(tone))}>{statusLabel}</span>
    </li>
  );
}

export function AutoPostMonitor({ projectId, className }: AutoPostMonitorProps) {
  const [data, setData] = useState<AutoPostMonitorSnapshot | null>(null);
  const [loading, setLoading] = useState(false);
  const [running, setRunning] = useState(false);
  const [error, setError] = useState("");
  const [logPanel, setLogPanel] = useState<LogPanel>(null);
  const [logs, setLogs] = useState<unknown[]>([]);
  const [logsLoading, setLogsLoading] = useState(false);
  const [copied, setCopied] = useState(false);
  const [tick, setTick] = useState(0);
  const [startingScheduler, setStartingScheduler] = useState(false);

  const fetchMonitor = useCallback(async () => {
    if (!projectId) return;
    setLoading(true);
    setError("");
    try {
      const res = await fetch(
        `/api/scheduling/auto-post-monitor?projectId=${encodeURIComponent(projectId)}`,
      );
      if (!res.ok) throw new Error("Failed to load auto-post status");
      const json = (await res.json()) as AutoPostMonitorSnapshot;
      setData(normalizeSnapshot(json));
    } catch (err) {
      setError(err instanceof Error ? err.message : "Failed to load status");
    } finally {
      setLoading(false);
    }
  }, [projectId]);

  useEffect(() => {
    void fetchMonitor();
    const interval = setInterval(() => void fetchMonitor(), 60_000);
    return () => clearInterval(interval);
  }, [fetchMonitor]);

  useEffect(() => {
    const timer = setInterval(() => setTick((t) => t + 1), 1000);
    return () => clearInterval(timer);
  }, []);

  const countdownMs = useMemo(() => {
    if (!data?.schedule.nextSlot) return null;
    const slot = data.schedule.nextSlot;
    const target = slot.isWindowActive ? slot.windowClosesAt : slot.windowOpensAt;
    const targetMs = new Date(target).getTime();
    if (Number.isNaN(targetMs)) return null;
    if (slot.isWindowActive) {
      return Math.max(0, targetMs - Date.now());
    }
    return Math.max(0, targetMs - Date.now());
  }, [data, tick]);

  const countdownLabel = useMemo(() => {
    if (countdownMs === null) return null;
    if (data?.schedule.nextSlot?.isWindowActive) {
      return `Window closes in ${formatCountdown(countdownMs)}`;
    }
    return `Starts in ${formatCountdown(countdownMs)}`;
  }, [countdownMs, data?.schedule.nextSlot?.isWindowActive]);

  const handleStartScheduler = async () => {
    setStartingScheduler(true);
    setError("");
    try {
      const res = await fetch("/api/scheduling/ensure-poller", { method: "POST" });
      const json = await res.json();
      if (!res.ok) throw new Error(json.error ?? "Could not start scheduler");
      await fetchMonitor();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Could not start scheduler");
    } finally {
      setStartingScheduler(false);
    }
  };

  const handleRunNow = async () => {
    setRunning(true);
    setError("");
    try {
      const res = await fetch("/api/scheduling/run-auto-post", { method: "POST" });
      const json = await res.json();
      if (!res.ok) throw new Error(json.error ?? "Manual run failed");
      await fetchMonitor();
    } catch (err) {
      setError(err instanceof Error ? err.message : "Manual run failed");
    } finally {
      setRunning(false);
    }
  };

  const loadLogs = async (panel: LogPanel) => {
    if (!panel || !projectId) return;
    setLogPanel(panel);
    setLogsLoading(true);
    try {
      const endpoint =
        panel === "scheduler"
          ? `/api/scheduling/auto-post-logs?projectId=${encodeURIComponent(projectId)}&limit=80`
          : `/api/scheduling/publish-logs?projectId=${encodeURIComponent(projectId)}&limit=80`;
      const res = await fetch(endpoint);
      const json = await res.json();
      setLogs(json.logs ?? []);
    } catch {
      setLogs([]);
    } finally {
      setLogsLoading(false);
    }
  };

  const handleCopyDebug = async () => {
    if (!data) return;
    try {
      const text = JSON.stringify(data, null, 2);
      await navigator.clipboard.writeText(text);
      setCopied(true);
      setTimeout(() => setCopied(false), 2000);
    } catch {
      setError("Could not copy to clipboard");
    }
  };

  if (!projectId) return null;

  return (
    <Card
      title="Auto-Post Monitor"
      subtitle="Scheduler status, next slot, platforms, and recent activity — no SSH required"
      className={cn("mb-6", className)}
    >
      {error && (
        <div className="mb-4 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700">
          {error}
        </div>
      )}

      {!data && loading ? (
        <div className="flex items-center gap-2 text-sm text-gray-500">
          <Loader2 className="h-4 w-4 animate-spin" />
          Loading auto-post status…
        </div>
      ) : data ? (
        <div className="space-y-6">
          <div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
            <div className="rounded-lg border border-gray-100 bg-gray-50/80 p-4">
              <p className="text-xs font-medium uppercase tracking-wide text-gray-500">Scheduler</p>
              <div className="mt-2 flex items-center gap-2">
                <span
                  className={cn("h-2.5 w-2.5 rounded-full", schedulerDot(data.scheduler.status))}
                />
                <span className="text-sm font-semibold text-gray-900">
                  {data.scheduler.statusLabel}
                </span>
              </div>
              {data.scheduler.lastRunAt && (
                <p className="mt-1 text-xs text-gray-500">
                  Last tick:{" "}
                  {formatMonitorTimestamp(
                    data.scheduler.lastRunAt,
                    data.timezone.iana ?? data.timezone.raw,
                  )}
                </p>
              )}
            </div>

            <div className="rounded-lg border border-gray-100 bg-gray-50/80 p-4">
              <p className="text-xs font-medium uppercase tracking-wide text-gray-500">
                Current time
              </p>
              <p className="mt-2 text-sm font-semibold text-gray-900">
                {data.timezone.currentTimeLocal}
              </p>
              <p className="mt-1 text-xs text-gray-500">
                {data.timezone.raw} ({data.timezone.label})
              </p>
            </div>

            <div className="rounded-lg border border-gray-100 bg-gray-50/80 p-4">
              <p className="text-xs font-medium uppercase tracking-wide text-gray-500">Status</p>
              <p className="mt-2 text-sm font-semibold text-gray-900">
                {data.schedule.statusLabel}
              </p>
              <p className="mt-1 text-xs text-gray-500">
                Window: ±{data.schedule.windowMinutes} min · {data.queuedCount} queued
              </p>
            </div>
          </div>

          <div className="rounded-lg border border-blue-100 bg-blue-50/50 p-4">
            <div className="flex flex-wrap items-start justify-between gap-3">
              <div>
                <p className="text-xs font-medium uppercase tracking-wide text-blue-800/70">
                  Next scheduled post
                </p>
                {data.schedule.nextSlot ? (
                  <div className="mt-2 space-y-1">
                    <p className="text-base font-semibold text-gray-900">
                      {data.schedule.nextSlot.dayLabel} · {data.schedule.nextSlot.slotTimeLocal}{" "}
                      {data.timezone.label}
                    </p>
                    <p className="text-sm text-gray-600">{data.schedule.nextSlot.display}</p>
                    <p className="text-xs text-gray-500">
                      All slots:{" "}
                      {data.schedule.plannedSlots.length > 0
                        ? data.schedule.plannedSlots.join(" · ")
                        : "—"}
                    </p>
                  </div>
                ) : (
                  <p className="mt-2 text-sm text-gray-600">No schedule configured</p>
                )}
              </div>
              {countdownLabel && (
                <div className="flex items-center gap-2 rounded-full bg-white px-3 py-1.5 text-sm font-medium text-blue-800 shadow-sm">
                  <Clock className="h-4 w-4" />
                  {countdownLabel}
                </div>
              )}
            </div>
            {data.schedule.activeSlotsNow.length > 0 && (
              <p className="mt-3 text-sm font-medium text-green-700">
                Active now: {data.schedule.activeSlotsNow.join(", ")}
              </p>
            )}
          </div>

          <div className="grid gap-4 md:grid-cols-2">
            <div>
              <p className="mb-2 text-xs font-medium uppercase tracking-wide text-gray-500">
                Platforms
              </p>
              {data.platforms.length > 0 ? (
                <ul className="space-y-2">
                  {data.platforms.map((p) => (
                    <PlatformRow
                      key={p.platform}
                      label={p.label}
                      statusLabel={p.statusLabel}
                      tone={p.statusTone}
                    />
                  ))}
                </ul>
              ) : (
                <p className="text-sm text-gray-500">No connected accounts</p>
              )}
            </div>

            <div className="space-y-3 text-sm">
              <div>
                <p className="text-xs font-medium uppercase tracking-wide text-gray-500">
                  Last attempt
                </p>
                {data.lastAttempt ? (
                  <p className="mt-1 text-gray-900">
                    {formatMonitorTimestamp(
                      data.lastAttempt.timestamp,
                      data.timezone.iana ?? data.timezone.raw,
                    )}
                    <span className="mx-1 text-gray-400">·</span>
                    <span className={toneClasses(data.lastAttempt.resultTone)}>
                      {data.lastAttempt.resultLabel}
                    </span>
                  </p>
                ) : (
                  <p className="mt-1 text-gray-500">No attempts logged yet</p>
                )}
              </div>

              <div>
                <p className="text-xs font-medium uppercase tracking-wide text-gray-500">
                  Last published
                </p>
                {data.lastPublished ? (
                  <p className="mt-1 text-gray-900">
                    {data.lastPublished.platform} ·{" "}
                    {formatMonitorTimestamp(data.lastPublished.timestamp)}
                  </p>
                ) : (
                  <p className="mt-1 text-gray-500">None yet</p>
                )}
              </div>

              {data.lastError && (
                <div className="rounded-md border border-red-100 bg-red-50 px-3 py-2">
                  <p className="text-xs font-medium text-red-800">Last error</p>
                  <p className="mt-1 text-xs text-red-700">{data.lastError.message}</p>
                </div>
              )}

              {!data.canAutoPost && data.executionStopsAt && (
                <div className="rounded-md border border-amber-100 bg-amber-50 px-3 py-2">
                  <p className="text-xs font-medium text-amber-900">Setup blocker</p>
                  <p className="mt-1 text-xs text-amber-800">
                    {humanizeMonitorBlocker(data.executionStopsAt)}
                  </p>
                  <p className="mt-1 text-xs text-amber-700">{data.summary}</p>
                  {data.executionStopsAt === "providers_validated" && (
                    <div className="mt-2">
                      <a
                        href="/connected-accounts"
                        className="text-xs font-medium text-amber-900 underline hover:text-amber-950"
                      >
                        Open Connected Accounts → reconnect LinkedIn
                      </a>
                    </div>
                  )}
                </div>
              )}

              {data.canAutoPost && data.queuedCount > 0 && data.schedule.status === "waiting" && (
                <div className="rounded-md border border-blue-100 bg-blue-50 px-3 py-2">
                  <p className="text-xs font-medium text-blue-900">Post queued — waiting for schedule</p>
                  <p className="mt-1 text-xs text-blue-800">
                    {data.queuedCount} post(s) queued. Cron publishes at the next morning/evening
                    slot (±{data.schedule.windowMinutes} min). No need to Generate again.
                  </p>
                  {data.schedule.nextSlot && (
                    <p className="mt-1 text-xs text-blue-700">
                      Next: {data.schedule.nextSlot.display} ({data.schedule.nextSlot.startsInLabel})
                    </p>
                  )}
                </div>
              )}

              {data.canAutoPost && data.schedule.status === "active_window" && data.queuedCount > 0 && (
                <div className="rounded-md border border-green-100 bg-green-50 px-3 py-2">
                  <p className="text-xs font-medium text-green-900">Inside schedule window</p>
                  <p className="mt-1 text-xs text-green-800">
                    {data.queuedCount} post(s) queued — auto-publish should fire within this window.
                  </p>
                </div>
              )}
            </div>
          </div>

          <div className="flex flex-wrap gap-2 border-t border-gray-100 pt-4">
            <Button
              type="button"
              variant="secondary"
              size="sm"
              disabled={loading}
              onClick={() => void fetchMonitor()}
            >
              {loading ? (
                <Loader2 className="h-4 w-4 animate-spin" />
              ) : (
                <RefreshCw className="h-4 w-4" />
              )}
              Refresh Status
            </Button>

            {data.scheduler.status === "stopped" && data.scheduler.cronSecretConfigured && (
              <Button
                type="button"
                variant="teal"
                size="sm"
                disabled={startingScheduler || loading}
                onClick={() => void handleStartScheduler()}
              >
                {startingScheduler ? (
                  <Loader2 className="h-4 w-4 animate-spin" />
                ) : (
                  <Play className="h-4 w-4" />
                )}
                Start Scheduler
              </Button>
            )}

            {data.allowManualRun && (
              <Button
                type="button"
                variant="purple"
                size="sm"
                disabled={running || loading}
                onClick={() => void handleRunNow()}
              >
                {running ? (
                  <Loader2 className="h-4 w-4 animate-spin" />
                ) : (
                  <Play className="h-4 w-4" />
                )}
                Run Auto-Post Now (publish queued)
              </Button>
            )}

            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={() => void loadLogs("scheduler")}
            >
              <ScrollText className="h-4 w-4" />
              Scheduler Logs
            </Button>

            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={() => void loadLogs("publish")}
            >
              <ScrollText className="h-4 w-4" />
              Publish Logs
            </Button>

            <Button type="button" variant="ghost" size="sm" onClick={() => void handleCopyDebug()}>
              <Copy className="h-4 w-4" />
              {copied ? "Copied!" : "Copy Debug Info"}
            </Button>
          </div>

          {logPanel && (
            <div className="rounded-lg border border-gray-200 bg-gray-950 p-4">
              <div className="mb-2 flex items-center justify-between">
                <p className="text-xs font-medium text-gray-300">
                  {logPanel === "scheduler" ? data.logFiles.autoPost : data.logFiles.publish}
                </p>
                <button
                  type="button"
                  className="text-xs text-gray-400 hover:text-white"
                  onClick={() => setLogPanel(null)}
                >
                  Close
                </button>
              </div>
              {logsLoading ? (
                <p className="text-xs text-gray-400">Loading logs…</p>
              ) : (
                <pre className="max-h-64 overflow-auto text-xs leading-relaxed text-green-300">
                  {logs.length > 0
                    ? logs.map((l) => JSON.stringify(l)).join("\n")
                    : "No log entries for this project today."}
                </pre>
              )}
            </div>
          )}
        </div>
      ) : null}
    </Card>
  );
}
