import React, { useEffect, useState, useCallback } from "react";
import { useParams, useNavigate, Link } from "react-router-dom";
import { api, openLogsWs, openAppLogsWs, formatUsd } from "../services/api";
import { StatusBadge } from "../components/StatusBadge";
import { LogViewer } from "../components/LogViewer";
import { ConfirmDialog } from "../components/ConfirmDialog";
import { usePageTitle } from "../hooks/usePageTitle";
import { toast } from "react-toastify";
import { ArrowLeft, CheckCircle2, RefreshCw } from "lucide-react";

interface Job {
  id: number;
  type: string;
  status: string;
  createdAt: string;
  startedAt: string | null;
  finishedAt: string | null;
  error: string | null;
}

interface Preview {
  id: number;
  prNumber: number;
  prTitle: string;
  commitSha: string;
  status: string;
  stopReason: string | null;
  instanceIp: string | null;
  port: number;
  logs: string;
  createdAt: string;
  updatedAt: string;
  stoppedAt: string | null;
  lastActivityAt: string;
  repoOwner: string;
  repoName: string;
  instanceType: string | null;
  costUsd: number;
  costRateUsd: number;
  jobs: Job[];
}

export function PreviewDetail() {
  const { id } = useParams<{ id: string }>();
  const previewId = parseInt(id || "0", 10);
  const navigate = useNavigate();
  const [preview, setPreview] = useState<Preview | null>(null);
  const [logs, setLogs] = useState("");
  const [appLogs, setAppLogs] = useState("");
  const [logTab, setLogTab] = useState<"deploy" | "app">("deploy");
  const [loading, setLoading] = useState(true);
  const [confirmStop, setConfirmStop] = useState(false);
  const [stopping, setStopping] = useState(false);
  const [rebuilding, setRebuilding] = useState(false);
  usePageTitle(preview ? `PR #${preview.prNumber} | ${preview.repoOwner}/${preview.repoName}` : `Preview ${previewId}`);

  const loadPreview = useCallback(async () => {
    const res = await api.previews.get(previewId);
    if (res.ok && res.data) {
      setPreview(res.data as Preview);
      setLogs(res.data.logs || "");
    } else if (res.status === 404) {
      navigate("/previews");
    }
    setLoading(false);
  }, [previewId, navigate]);

  useEffect(() => {
    loadPreview();
    const interval = setInterval(loadPreview, 5000);
    return () => clearInterval(interval);
  }, [loadPreview]);

  useEffect(() => {
    if (!preview) return;
    if (preview.status !== "RUNNING" && preview.status !== "BUILDING" && preview.status !== "PROVISIONING") return;

    const ws = openLogsWs(previewId, (msg) => {
      if (msg.type === "init") setLogs(msg.logs || "");
      else if (msg.type === "append") setLogs(prev => prev + msg.text);
    });

    return () => { try { ws.close(); } catch {} };
  }, [preview?.status, previewId]);

  // Live app-process logs are only meaningful once the app is actually running.
  // Reset and re-open the stream whenever the running instance changes.
  useEffect(() => {
    if (preview?.status !== "RUNNING") return;

    setAppLogs("");
    const ws = openAppLogsWs(previewId, (msg) => {
      if (msg.type === "append") setAppLogs(prev => prev + msg.text);
    });

    return () => { try { ws.close(); } catch {} };
  }, [preview?.status, preview?.instanceIp, previewId]);

  const handleStop = async () => {
    setStopping(true);
    const res = await api.previews.stop(previewId);
    setStopping(false);
    setConfirmStop(false);
    if (res.ok) toast.success("Stop job enqueued");
    else toast.error(res.message || "Failed to enqueue stop");
    await loadPreview();
  };

  const handleRebuild = async () => {
    setRebuilding(true);
    const res = await api.previews.rebuild(previewId);
    setRebuilding(false);
    if (res.ok) toast.success("Rebuild job enqueued");
    else toast.error(res.message || "Failed to enqueue rebuild");
    await loadPreview();
  };

  if (loading) {
    return (
      <div className="space-y-4 animate-pulse">
        <div className="h-8 bg-gray-200 dark:bg-slate-700 rounded w-64" />
        <div className="h-4 bg-gray-200 dark:bg-slate-700 rounded w-96" />
        <div className="h-96 bg-gray-200 dark:bg-slate-700 rounded" />
      </div>
    );
  }

  if (!preview) return null;

  return (
    <div className="space-y-6">
      <ConfirmDialog
        open={confirmStop}
        title="Stop Preview"
        message="Are you sure you want to stop this preview? The EC2 instance will be terminated."
        confirmLabel="Stop Preview"
        onConfirm={handleStop}
        onCancel={() => setConfirmStop(false)}
        danger
      />

      <div>
        <Link to="/previews" className="inline-flex items-center gap-1 text-sm text-blue-600 dark:text-blue-400 hover:underline mb-2">
          <ArrowLeft size={14} /> Back to Previews
        </Link>
        <div className="flex items-start justify-between gap-4">
          <div>
            <h1 className="text-2xl font-bold">
              {preview.repoOwner}/{preview.repoName} — PR #{preview.prNumber}
            </h1>
            <p className="text-gray-600 dark:text-slate-300 mt-1">{preview.prTitle}</p>
          </div>
          <div className="flex items-center gap-2 shrink-0">
            <StatusBadge status={preview.status as any} reason={preview.stopReason} />
            {preview.status !== "IGNORED" && (
              <button
                onClick={handleRebuild}
                disabled={rebuilding}
                className="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300 hover:bg-blue-200 dark:hover:bg-blue-900/60 rounded-lg transition-colors disabled:opacity-50"
              >
                <RefreshCw size={14} className={rebuilding ? "animate-spin" : ""} />
                Rebuild
              </button>
            )}
            {preview.status !== "STOPPED" && preview.status !== "IGNORED" && (
              <button
                onClick={() => setConfirmStop(true)}
                disabled={stopping}
                className="px-3 py-1.5 text-sm bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300 hover:bg-red-200 dark:hover:bg-red-900/60 rounded-lg transition-colors disabled:opacity-50"
              >
                Stop
              </button>
            )}
          </div>
        </div>
      </div>

      <div className="grid grid-cols-2 md:grid-cols-4 gap-4">
        <InfoCard label="Commit" value={preview.commitSha.slice(0, 8)} mono />
        <InfoCard label="Port" value={String(preview.port)} />
        <InfoCard label="Created" value={new Date(preview.createdAt).toLocaleDateString()} />
        <InfoCard label="Last Activity" value={new Date(preview.lastActivityAt).toLocaleString()} />
        {preview.status === "STOPPED" && (
          <InfoCard label="Stop Reason" value={preview.stopReason || "Stopped"} />
        )}
        <InfoCard
          label="Est. Cost"
          value={
            formatUsd(preview.costUsd) +
            (preview.costRateUsd > 0 ? ` (${formatUsd(preview.costRateUsd)}/hr)` : "")
          }
        />
        <InfoCard label="Instance" value={preview.instanceType || "—"} mono />
      </div>

      {preview.status === "RUNNING" && preview.instanceIp && (
        <div className="bg-green-50 dark:bg-green-900/20 border border-green-200 dark:border-green-800 rounded-xl p-4">
          <p className="inline-flex items-center gap-1.5 text-sm font-medium text-green-800 dark:text-green-300 mb-1"><CheckCircle2 size={16} /> Preview Live</p>
          <a
            href={`http://${preview.instanceIp}:${preview.port}`}
            target="_blank"
            rel="noreferrer"
            className="text-green-700 dark:text-green-400 hover:underline font-mono text-sm"
          >
            http://{preview.instanceIp}:{preview.port}
          </a>
        </div>
      )}

      <div>
        <div className="flex items-center gap-2 mb-3">
          <h2 className="text-lg font-semibold mr-2">Logs</h2>
          <button
            onClick={() => setLogTab("deploy")}
            className={`px-3 py-1 text-sm rounded-lg transition-colors ${
              logTab === "deploy"
                ? "bg-blue-600 text-white"
                : "bg-gray-100 dark:bg-slate-800 text-gray-600 dark:text-slate-300 hover:bg-gray-200 dark:hover:bg-slate-700"
            }`}
          >
            Deploy
          </button>
          <button
            onClick={() => setLogTab("app")}
            className={`px-3 py-1 text-sm rounded-lg transition-colors ${
              logTab === "app"
                ? "bg-blue-600 text-white"
                : "bg-gray-100 dark:bg-slate-800 text-gray-600 dark:text-slate-300 hover:bg-gray-200 dark:hover:bg-slate-700"
            }`}
          >
            App
          </button>
        </div>
        {logTab === "deploy" ? (
          <LogViewer logs={logs} autoScroll maxHeight="600px" />
        ) : preview.status === "RUNNING" ? (
          <LogViewer
            logs={appLogs || "Connecting to app log stream…"}
            autoScroll
            maxHeight="600px"
          />
        ) : (
          <div className="bg-slate-50 dark:bg-black rounded-lg p-4 border border-slate-200 dark:border-gray-800 text-sm text-gray-500 dark:text-slate-400">
            App logs are only available while the preview is live.
          </div>
        )}
      </div>

      <div>
        <h2 className="text-lg font-semibold mb-3">Job History</h2>
        <div className="space-y-2">
          {preview.jobs.length === 0 ? (
            <p className="text-sm text-gray-500 dark:text-slate-400">No jobs yet.</p>
          ) : preview.jobs.map(job => (
            <div key={job.id} className="flex items-center gap-3 bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg p-3">
              <span className="text-xs font-mono bg-gray-100 dark:bg-slate-700 px-2 py-0.5 rounded">{job.type}</span>
              <span className={`text-xs px-2 py-0.5 rounded-full ${
                job.status === "DONE" ? "bg-green-100 text-green-700 dark:bg-green-900/30 dark:text-green-300" :
                job.status === "FAILED" ? "bg-red-100 text-red-700 dark:bg-red-900/30 dark:text-red-300" :
                job.status === "RUNNING" ? "bg-yellow-100 text-yellow-700 dark:bg-yellow-900/30 dark:text-yellow-300" :
                "bg-gray-100 text-gray-600 dark:bg-slate-700 dark:text-slate-300"
              }`}>{job.status}</span>
              <span className="text-xs text-gray-500 dark:text-slate-400">{new Date(job.createdAt).toLocaleString()}</span>
              {job.error && (
                <span className="text-xs text-red-600 dark:text-red-400 truncate max-w-xs" title={job.error}>{job.error}</span>
              )}
            </div>
          ))}
        </div>
      </div>
    </div>
  );
}

function InfoCard({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
  return (
    <div className="bg-white dark:bg-slate-800 border border-gray-200 dark:border-slate-700 rounded-lg p-3">
      <p className="text-xs text-gray-500 dark:text-slate-400 mb-1">{label}</p>
      <p className={`text-sm font-medium truncate ${mono ? "font-mono" : ""}`}>{value}</p>
    </div>
  );
}
