import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { toast } from "sonner";
import { Loader2, GitBranch, ArrowRight, FileCode, Plus, Minus, Upload, GitMerge, AlertTriangle, CheckCircle2 } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { trpc } from "@/lib/trpc";
import { parseUnifiedDiff } from "./parse-diff";
import { DiffViewer } from "./DiffViewer";
import { ReviewSidebar } from "./ReviewSidebar";
import { PreviewControls } from "./PreviewControls";
import { ConflictResolutionPanel } from "./ConflictResolutionPanel";

interface InitiativeReviewProps {
  initiativeId: string;
  onCompleted: () => void;
}

export function InitiativeReview({ initiativeId, onCompleted }: InitiativeReviewProps) {
  const [selectedCommit, setSelectedCommit] = useState<string | null>(null);
  const [viewedFiles, setViewedFiles] = useState<Set<string>>(new Set());
  const fileRefs = useRef<Map<string, HTMLDivElement>>(new Map());

  const toggleViewed = useCallback((filePath: string) => {
    setViewedFiles((prev) => {
      const next = new Set(prev);
      if (next.has(filePath)) next.delete(filePath);
      else next.add(filePath);
      return next;
    });
  }, []);

  const registerFileRef = useCallback((filePath: string, el: HTMLDivElement | null) => {
    if (el) fileRefs.current.set(filePath, el);
    else fileRefs.current.delete(filePath);
  }, []);

  // Fetch initiative diff
  const diffQuery = trpc.getInitiativeReviewDiff.useQuery(
    { initiativeId },
  );

  // Fetch initiative commits
  const commitsQuery = trpc.getInitiativeReviewCommits.useQuery(
    { initiativeId },
  );
  const commits = commitsQuery.data?.commits ?? [];

  // Fetch single-commit diff
  const commitDiffQuery = trpc.getInitiativeCommitDiff.useQuery(
    { initiativeId, commitHash: selectedCommit! },
    { enabled: !!selectedCommit },
  );

  // Mergeability check
  const mergeabilityQuery = trpc.checkInitiativeMergeability.useQuery(
    { initiativeId },
    { refetchInterval: 30_000 },
  );
  const mergeability = mergeabilityQuery.data ?? null;

  // Auto-refresh mergeability when a conflict agent completes
  const conflictAgentQuery = trpc.getActiveConflictAgent.useQuery({ initiativeId });
  const conflictAgentStatus = conflictAgentQuery.data?.status;
  const prevConflictStatusRef = useRef(conflictAgentStatus);
  useEffect(() => {
    const prev = prevConflictStatusRef.current;
    prevConflictStatusRef.current = conflictAgentStatus;
    // When agent transitions from running/waiting to idle (completed)
    if (prev && ['running', 'waiting_for_input'].includes(prev) && conflictAgentStatus === 'idle') {
      void mergeabilityQuery.refetch();
      void diffQuery.refetch();
      void commitsQuery.refetch();
    }
  }, [conflictAgentStatus, mergeabilityQuery, diffQuery, commitsQuery]);

  // Preview state
  const projectsQuery = trpc.getInitiativeProjects.useQuery({ initiativeId });
  const firstProjectId = projectsQuery.data?.[0]?.id ?? null;

  const previewsQuery = trpc.listPreviews.useQuery({ initiativeId });
  const existingPreview = previewsQuery.data?.find(
    (p) => p.initiativeId === initiativeId,
  );
  const [activePreviewId, setActivePreviewId] = useState<string | null>(null);
  const previewStatusQuery = trpc.getPreviewStatus.useQuery(
    { previewId: activePreviewId ?? existingPreview?.id ?? "" },
    { enabled: !!(activePreviewId ?? existingPreview?.id) },
  );
  const preview = previewStatusQuery.data ?? existingPreview;

  const startPreview = trpc.startPreview.useMutation({
    onSuccess: (data) => {
      setActivePreviewId(data.id);
      previewsQuery.refetch();
      toast.success(`Preview running at ${data.url}`);
    },
    onError: (err) => toast.error(`Preview failed: ${err.message}`),
  });

  const stopPreview = trpc.stopPreview.useMutation({
    onSuccess: () => {
      setActivePreviewId(null);
      toast.success("Preview stopped");
      previewsQuery.refetch();
    },
    onError: (err) => toast.error(`Failed to stop: ${err.message}`),
  });

  const approveMutation = trpc.approveInitiativeReview.useMutation({
    onSuccess: (_data, variables) => {
      const msg = variables.strategy === "merge_and_push"
        ? "Initiative merged into default branch and pushed"
        : "Initiative branch pushed to remote";
      toast.success(msg);
      onCompleted();
    },
    onError: (err) => toast.error(err.message),
  });

  const activeDiffRaw = selectedCommit
    ? commitDiffQuery.data?.rawDiff
    : diffQuery.data?.rawDiff;

  const files = useMemo(() => {
    if (!activeDiffRaw) return [];
    return parseUnifiedDiff(activeDiffRaw);
  }, [activeDiffRaw]);

  const isDiffLoading = selectedCommit
    ? commitDiffQuery.isLoading
    : diffQuery.isLoading;

  const allFiles = useMemo(() => {
    if (!diffQuery.data?.rawDiff) return [];
    return parseUnifiedDiff(diffQuery.data.rawDiff);
  }, [diffQuery.data?.rawDiff]);

  const handleFileClick = useCallback((filePath: string) => {
    const el = fileRefs.current.get(filePath);
    if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
  }, []);

  const totalAdditions = allFiles.reduce((s, f) => s + f.additions, 0);
  const totalDeletions = allFiles.reduce((s, f) => s + f.deletions, 0);
  const sourceBranch = diffQuery.data?.sourceBranch ?? "";
  const targetBranch = diffQuery.data?.targetBranch ?? "";

  const previewState = firstProjectId && sourceBranch
    ? {
        status: preview?.status === "running"
          ? ("running" as const)
          : preview?.status === "failed"
            ? ("failed" as const)
            : (startPreview.isPending || preview?.status === "building")
              ? ("building" as const)
              : ("idle" as const),
        url: preview?.url ?? undefined,
        onStart: () =>
          startPreview.mutate({
            initiativeId,
            projectId: firstProjectId,
            branch: sourceBranch,
          }),
        onStop: () => {
          const id = activePreviewId ?? existingPreview?.id;
          if (id) stopPreview.mutate({ previewId: id });
        },
        isStarting: startPreview.isPending,
        isStopping: stopPreview.isPending,
      }
    : null;

  return (
    <div className="rounded-lg border border-border overflow-hidden bg-card">
      {/* Header */}
      <div className="border-b border-border bg-card/80 backdrop-blur-sm">
        <div className="flex items-center gap-3 px-4 py-2.5">
          {/* Left: branch info + stats */}
          <div className="flex items-center gap-3 min-w-0 flex-1">
            <h2 className="text-sm font-semibold truncate shrink-0">
              Initiative Review
            </h2>

            {sourceBranch && (
              <div className="flex items-center gap-1 text-[11px] text-muted-foreground font-mono min-w-0">
                <GitBranch className="h-3 w-3 shrink-0" />
                <span className="truncate" title={sourceBranch}>
                  {sourceBranch}
                </span>
                <ArrowRight className="h-2.5 w-2.5 shrink-0 text-muted-foreground/50" />
                <span className="truncate" title={targetBranch}>
                  {targetBranch}
                </span>
              </div>
            )}

            <div className="flex items-center gap-2.5 text-[11px] shrink-0">
              <span className="flex items-center gap-0.5 text-muted-foreground">
                <FileCode className="h-3 w-3" />
                {allFiles.length}
              </span>
              <span className="flex items-center gap-0.5 text-diff-add-fg">
                <Plus className="h-3 w-3" />
                {totalAdditions}
              </span>
              <span className="flex items-center gap-0.5 text-diff-remove-fg">
                <Minus className="h-3 w-3" />
                {totalDeletions}
              </span>
            </div>

            {/* Mergeability badge */}
            {mergeabilityQuery.isLoading ? (
              <Badge variant="secondary" className="text-[10px] h-5">
                <Loader2 className="h-2.5 w-2.5 animate-spin mr-1" />
                Checking...
              </Badge>
            ) : mergeability?.mergeable ? (
              <Badge variant="success" className="text-[10px] h-5">
                <CheckCircle2 className="h-2.5 w-2.5 mr-1" />
                Clean merge
              </Badge>
            ) : mergeability && !mergeability.mergeable ? (
              <Badge variant="error" className="text-[10px] h-5">
                <AlertTriangle className="h-2.5 w-2.5 mr-1" />
                {mergeability.conflictFiles.length} conflict{mergeability.conflictFiles.length !== 1 ? 's' : ''}
              </Badge>
            ) : null}
          </div>

          {/* Right: preview + action buttons */}
          <div className="flex items-center gap-2 shrink-0">
            {previewState && <PreviewControls preview={previewState} />}
            <Button
              variant="outline"
              size="sm"
              onClick={() => approveMutation.mutate({ initiativeId, strategy: "push_branch" })}
              disabled={approveMutation.isPending}
              className="h-8 text-xs px-3"
            >
              {approveMutation.isPending ? (
                <Loader2 className="h-3 w-3 animate-spin" />
              ) : (
                <Upload className="h-3 w-3" />
              )}
              Push Branch
            </Button>
            <Button
              size="sm"
              onClick={() => approveMutation.mutate({ initiativeId, strategy: "merge_and_push" })}
              disabled={approveMutation.isPending || mergeability?.mergeable === false}
              title={mergeability?.mergeable === false ? 'Resolve merge conflicts before merging' : undefined}
              className="h-9 px-5 text-sm font-semibold shadow-sm"
            >
              {approveMutation.isPending ? (
                <Loader2 className="h-3.5 w-3.5 animate-spin" />
              ) : (
                <GitMerge className="h-3.5 w-3.5" />
              )}
              Merge & Push to {targetBranch || "default"}
            </Button>
          </div>
        </div>
      </div>

      {/* Conflict resolution panel */}
      {mergeability && !mergeability.mergeable && (
        <ConflictResolutionPanel
          initiativeId={initiativeId}
          conflicts={mergeability.conflictFiles}
          onResolved={() => {
            void mergeabilityQuery.refetch();
            void diffQuery.refetch();
            void commitsQuery.refetch();
          }}
        />
      )}

      {/* Main content */}
      <div className="grid grid-cols-1 lg:grid-cols-[260px_1fr]">
        <div className="border-r border-border">
          <div className="sticky top-0 h-[calc(100vh-12rem)]">
            <ReviewSidebar
              files={allFiles}
              comments={[]}
              onFileClick={handleFileClick}
              selectedCommit={selectedCommit}
              activeFiles={files}
              commits={commits}
              onSelectCommit={setSelectedCommit}
              viewedFiles={viewedFiles}
            />
          </div>
        </div>

        <div className="min-w-0 p-4">
          {isDiffLoading ? (
            <div className="flex h-64 items-center justify-center text-muted-foreground gap-2">
              <Loader2 className="h-4 w-4 animate-spin" />
              Loading diff...
            </div>
          ) : files.length === 0 ? (
            <div className="flex h-32 items-center justify-center text-muted-foreground text-sm">
              {selectedCommit
                ? "No changes in this commit"
                : "No changes in this initiative"}
            </div>
          ) : (
            <DiffViewer
              files={files}
              comments={[]}
              onAddComment={() => {}}
              onResolveComment={() => {}}
              onUnresolveComment={() => {}}
              viewedFiles={viewedFiles}
              onToggleViewed={toggleViewed}
              onRegisterRef={registerFileRef}
            />
          )}
        </div>
      </div>
    </div>
  );
}
