import { gitBranchCreate, gitBranchDelete, gitBranchList, gitBranchSummary, gitMergeAnalysis, gitMergeAnalysisForRef, gitMergeTrees, gitBranchCurrent, gitBranchDiff, gitBranchRename, gitBranchDeleteRemote, gitBranchMove } from "@/client";
import { RepoHeader } from "@/components/repository/header";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { GitBranch, Loader2, Plus, Search, Trash2, GitMerge, ArrowRight, Edit, CloudOff } from "lucide-react";
import { useMemo, useState } from "react";
import { useParams } from "react-router-dom";
import { Badge } from "@/components/ui/badge";
import type { BranchInfoResponse } from "@/client";
import { toast } from "sonner";

export const RepoBranches = () => {
  const { namespace, repoName } = useParams<{ namespace: string; repoName: string }>();
  const queryClient = useQueryClient();

  const [searchQuery, setSearchQuery] = useState("");
  const [showCreate, setShowCreate] = useState(false);
  const [newBranchName, setNewBranchName] = useState("");
  const [sourceBranch, setSourceBranch] = useState("");
  const [compareBranch, setCompareBranch] = useState<string | null>(null);
  const [showDiff, setShowDiff] = useState(false);
  const [renameBranch, setRenameBranch] = useState<string | null>(null);
  const [moveBranch, setMoveBranch] = useState<string | null>(null);
  const [moveTarget, setMoveTarget] = useState("");

  const { data: branches = [], isLoading, isFetching } = useQuery({
    queryKey: ["repo-branches", namespace, repoName],
    queryFn: async () => {
      if (!namespace || !repoName) return [];
      const resp = await gitBranchList({ path: { namespace, repo: repoName } });
      return resp.data?.data ?? [];
    },
    enabled: !!namespace && !!repoName,
    staleTime: 30 * 1000,
  });

  const { data: branchSummary } = useQuery({
    queryKey: ["repo-branch-summary", namespace, repoName],
    queryFn: async () => {
      if (!namespace || !repoName) return null;
      const resp = await gitBranchSummary({ path: { namespace, repo: repoName } });
      return resp.data?.data ?? null;
    },
    enabled: !!namespace && !!repoName,
    staleTime: 60 * 1000,
  });

  // Get current branch
  const { data: currentBranchData } = useQuery({
    queryKey: ["repo-current-branch", namespace, repoName],
    queryFn: async () => {
      if (!namespace || !repoName) return null;
      const resp = await gitBranchCurrent({ path: { namespace, repo: repoName } });
      return resp.data?.data ?? null;
    },
    enabled: !!namespace && !!repoName,
    staleTime: 30 * 1000,
  });

  // Get merge analysis for branches
  const { data: mergeAnalysisData } = useQuery({
    queryKey: ["repo-merge-analysis", namespace, repoName],
    queryFn: async () => {
      if (!namespace || !repoName) return null;
      const resp = await gitMergeAnalysis({ path: { namespace, repo: repoName, their_oid: currentBranchData?.oid ?? "" } });
      return resp.data?.data ?? null;
    },
    enabled: !!namespace && !!repoName && !!currentBranchData?.oid,
    staleTime: 60 * 1000,
  });

  // Get merge analysis for specific ref (check if branch can be merged)
  const { data: mergeAnalysisForRefData } = useQuery({
    queryKey: ["repo-merge-analysis-for-ref", namespace, repoName, compareBranch],
    queryFn: async () => {
      if (!namespace || !repoName || !compareBranch || !currentBranchData?.oid) return null;
      const resp = await gitMergeAnalysisForRef({
        path: { namespace, repo: repoName, ref_name: compareBranch, their_oid: currentBranchData.oid },
      });
      return resp.data?.data ?? null;
    },
    enabled: !!namespace && !!repoName && !!compareBranch && !!currentBranchData?.oid,
    staleTime: 30 * 1000,
  });

  // Get branch diff for comparison (SDK doesn't support query params - disabled)
  const { data: branchDiffData, isLoading: diffLoading } = useQuery({
    queryKey: ["repo-branch-diff", namespace, repoName, compareBranch],
    queryFn: async () => {
      if (!namespace || !repoName || !compareBranch) return null;
      const resp = await gitBranchDiff({
        path: { namespace, repo: repoName },
      });
      return resp.data?.data ?? null;
    },
    enabled: false, // requires query params not in current SDK
    staleTime: 30 * 1000,
  });

  const createMutation = useMutation({
    mutationFn: async () => {
      if (!namespace || !repoName) return;
      await gitBranchCreate({
        path: { namespace, repo: repoName },
        body: { name: newBranchName },
      });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-branches", namespace, repoName] });
      setShowCreate(false);
      setNewBranchName("");
      setSourceBranch("");
    },
  });

  const deleteMutation = useMutation({
    mutationFn: async (branchName: string) => {
      if (!namespace || !repoName) return;
      await gitBranchDelete({
        path: { namespace, repo: repoName, name: branchName },
      });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-branches", namespace, repoName] });
    },
  });

  const renameMutation = useMutation({
    mutationFn: async ({ oldName, newName }: { oldName: string; newName: string }) => {
      if (!namespace || !repoName) return;
      await gitBranchRename({
        path: { namespace, repo: repoName },
        body: { old_name: oldName, new_name: newName },
      });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-branches", namespace, repoName] });
      toast.success("Branch renamed");
    },
    onError: () => {
      toast.error("Failed to rename branch");
    },
  });

  // Move branch to different commit
  const moveMutation = useMutation({
    mutationFn: async ({ branchName, target }: { branchName: string; target: string }) => {
      if (!namespace || !repoName) return;
      await gitBranchMove({
        path: { namespace, repo: repoName },
        body: { name: branchName, new_name: target },
      });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-branches", namespace, repoName] });
      toast.success("Branch moved");
    },
    onError: () => {
      toast.error("Failed to move branch");
    },
  });

  const deleteRemoteMutation = useMutation({
    mutationFn: async (branchName: string) => {
      if (!namespace || !repoName) return;
      await gitBranchDeleteRemote({
        path: { namespace, repo: repoName, name: branchName },
      });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-branches", namespace, repoName] });
      toast.success("Remote branch deleted");
    },
    onError: () => {
      toast.error("Failed to delete remote branch");
    },
  });

  // Merge branches
  const mergeMutation = useMutation({
    mutationFn: async ({ from, to }: { from: string; to: string }) => {
      if (!namespace || !repoName) return;
      await gitMergeTrees({
        path: { namespace, repo: repoName },
        body: { ancestor_oid: currentBranchData?.oid ?? "main", our_oid: to, their_oid: from },
      });
    },
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["repo-branches", namespace, repoName] });
      queryClient.invalidateQueries({ queryKey: ["repo-merge-analysis", namespace, repoName] });
      toast.success("Merge completed successfully");
      setShowDiff(false);
      setCompareBranch(null);
    },
    onError: (error: Error) => {
      toast.error(`Merge failed: ${error.message}`);
    },
  });

  const filtered: BranchInfoResponse[] = useMemo(() => {
    if (!searchQuery.trim()) return branches as BranchInfoResponse[];
    const q = searchQuery.toLowerCase();
    return (branches as BranchInfoResponse[]).filter((b) => b.name.toLowerCase().includes(q));
  }, [branches, searchQuery]);

  if (isLoading) {
    return (
      <div className="flex items-center justify-center h-64">
        <Loader2 className="h-6 w-6 animate-spin" />
      </div>
    );
  }

  return (
    <>
      <div className="p-6 pb-0 max-w-5xl mx-auto space-y-6">
        <RepoHeader />
      </div>
      <div className="p-6 pt-0 max-w-5xl mx-auto space-y-4">
        <div className="flex items-center justify-between py-4">
          <div className="flex items-center gap-2">
            <GitBranch className="h-5 w-5 text-muted-foreground" />
            <h2 className="text-lg font-semibold">Branches</h2>
            <span className="text-sm text-muted-foreground">({filtered.length})</span>
            {isFetching && <Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />}
          </div>
          <div className="flex items-center gap-4 text-sm text-muted-foreground">
            {branchSummary && (
              <>
                <span>{branchSummary.local_count} local</span>
                <span>{branchSummary.remote_count} remote</span>
              </>
            )}
            {currentBranchData && (
              <span className="flex items-center gap-1">
                <ArrowRight className="h-3 w-3" />
                {currentBranchData.name?.replace("refs/heads/", "")}
              </span>
            )}
            {mergeAnalysisData && (
              <span className="flex items-center gap-1 text-green-600">
                <GitMerge className="h-3 w-3" />
                {mergeAnalysisData && mergeAnalysisData.supported_strategies.length > 0 ? "Mergeable" : "Conflicts"}
              </span>
            )}
            <Button size="sm" onClick={() => setShowCreate(true)}>
              <Plus className="h-4 w-4 mr-1" />
              New branch
            </Button>
            <Button size="sm" variant="outline" onClick={() => setShowDiff(!showDiff)}>
              <GitMerge className="h-4 w-4 mr-1" />
              Compare
            </Button>
          </div>
        </div>

        <div className="relative max-w-sm">
          <Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" />
          <Input
            placeholder="Search branches..."
            value={searchQuery}
            onChange={(e) => setSearchQuery(e.target.value)}
            className="pl-9"
          />
        </div>

        {showCreate && (
          <div className="border rounded-md p-4 space-y-3">
            <h3 className="font-medium">Create new branch</h3>
            <div className="grid grid-cols-2 gap-3">
              <div>
                <Label>Branch name</Label>
                <Input
                  value={newBranchName}
                  onChange={(e) => setNewBranchName(e.target.value)}
                  placeholder="feature/my-branch"
                  className="mt-1"
                />
              </div>
              <div>
                <Label>Create from (optional)</Label>
                <Input
                  value={sourceBranch}
                  onChange={(e) => setSourceBranch(e.target.value)}
                  placeholder="main"
                  className="mt-1"
                />
              </div>
            </div>
            <div className="flex gap-2">
              <Button
                size="sm"
                onClick={() => createMutation.mutate()}
                disabled={!newBranchName.trim() || createMutation.isPending}
              >
                {createMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin" /> : "Create"}
              </Button>
              <Button size="sm" variant="outline" onClick={() => setShowCreate(false)}>
                Cancel
              </Button>
            </div>
          </div>
        )}

        {/* Rename branch dialog */}
        {renameBranch && (
          <div className="border rounded-md p-4 space-y-3">
            <div className="flex items-center justify-between">
              <h3 className="font-medium">Rename Branch</h3>
              <Button size="sm" variant="ghost" onClick={() => setRenameBranch(null)}>
                <Trash2 className="h-4 w-4" />
              </Button>
            </div>
            <div className="grid grid-cols-2 gap-3">
              <div>
                <Label>Current name</Label>
                <Input value={renameBranch.replace("refs/heads/", "")} disabled className="mt-1" />
              </div>
              <div>
                <Label>New name</Label>
                <Input
                  value={newBranchName}
                  onChange={(e) => setNewBranchName(e.target.value)}
                  placeholder="new-branch-name"
                  className="mt-1"
                />
              </div>
            </div>
            <div className="flex gap-2">
              <Button
                size="sm"
                onClick={() => {
                  if (newBranchName.trim() && renameBranch) {
                    renameMutation.mutate({
                      oldName: renameBranch.replace("refs/heads/", ""),
                      newName: newBranchName.trim(),
                    });
                    setRenameBranch(null);
                  }
                }}
                disabled={!newBranchName.trim() || renameMutation.isPending}
              >
                {renameMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin" /> : "Rename"}
              </Button>
              <Button size="sm" variant="outline" onClick={() => setRenameBranch(null)}>
                Cancel
              </Button>
            </div>
          </div>
        )}

        {/* Move branch dialog */}
        {moveBranch && (
          <div className="border rounded-md p-4 space-y-3">
            <div className="flex items-center justify-between">
              <h3 className="font-medium">Move Branch</h3>
              <Button size="sm" variant="ghost" onClick={() => setMoveBranch(null)}>
                <Trash2 className="h-4 w-4" />
              </Button>
            </div>
            <div className="grid grid-cols-2 gap-3">
              <div>
                <Label>Branch</Label>
                <Input value={moveBranch.replace("refs/heads/", "")} disabled className="mt-1" />
              </div>
              <div>
                <Label>Target commit</Label>
                <Input
                  value={moveTarget}
                  onChange={(e) => setMoveTarget(e.target.value)}
                  placeholder="commit-sha or ref"
                  className="mt-1"
                />
              </div>
            </div>
            <div className="flex gap-2">
              <Button
                size="sm"
                onClick={() => {
                  if (moveTarget.trim() && moveBranch) {
                    moveMutation.mutate({
                      branchName: moveBranch.replace("refs/heads/", ""),
                      target: moveTarget.trim(),
                    });
                    setMoveBranch(null);
                  }
                }}
                disabled={!moveTarget.trim() || moveMutation.isPending}
              >
                {moveMutation.isPending ? <Loader2 className="h-4 w-4 animate-spin" /> : "Move"}
              </Button>
              <Button size="sm" variant="outline" onClick={() => setMoveBranch(null)}>
                Cancel
              </Button>
            </div>
          </div>
        )}

        {/* Branch comparison panel */}
        {showDiff && (
          <div className="border rounded-md p-4 space-y-3">
            <div className="flex items-center justify-between">
              <h3 className="font-medium">Compare Branches</h3>
              <Button size="sm" variant="ghost" onClick={() => setShowDiff(false)}>
                <Trash2 className="h-4 w-4" />
              </Button>
            </div>
            <div className="flex items-center gap-2">
              <Label>Compare</Label>
              <select
                className="border rounded px-2 py-1 text-sm"
                value={compareBranch || ""}
                onChange={(e) => setCompareBranch(e.target.value || null)}
              >
                <option value="">Select branch</option>
                {branches.map((b: BranchInfoResponse) => (
                  <option key={b.name} value={b.name.replace("refs/heads/", "")}>
                    {b.name.replace("refs/heads/", "")}
                  </option>
                ))}
              </select>
              <span className="text-muted-foreground">→</span>
              <span className="font-medium">{currentBranchData?.name?.replace("refs/heads/", "")}</span>
            </div>

            {/* Merge analysis status */}
            {mergeAnalysisForRefData && compareBranch && (
              <div className="flex items-center gap-3 p-3 bg-muted/50 rounded-md">
                <div className="flex items-center gap-2">
                  {mergeAnalysisForRefData.supported_strategies.length > 0 ? (
                    <>
                      <GitMerge className="h-4 w-4 text-green-600" />
                      <span className="text-sm text-green-600 font-medium">Can merge automatically</span>
                    </>
                  ) : (
                    <>
                      <GitMerge className="h-4 w-4 text-orange-600" />
                      <span className="text-sm text-orange-600 font-medium">Cannot auto-merge (conflicts)</span>
                    </>
                  )}
                </div>
                {branchDiffData && "ahead" in branchDiffData && (
                  <span className="text-xs text-muted-foreground">
                    {branchDiffData.ahead} commit(s) ahead
                  </span>
                )}
                {branchDiffData && "behind" in branchDiffData && (
                  <span className="text-xs text-muted-foreground">
                    {branchDiffData.behind} commit(s) behind
                  </span>
                )}
              </div>
            )}

            {diffLoading && (
              <div className="flex items-center gap-2 text-muted-foreground">
                <Loader2 className="h-4 w-4 animate-spin" />
                <span className="text-sm">Loading diff...</span>
              </div>
            )}
            {branchDiffData && !diffLoading && (
              <div className="bg-muted/50 rounded-md p-3 text-xs font-mono max-h-60 overflow-auto">
                <pre>{JSON.stringify(branchDiffData, null, 2)}</pre>
              </div>
            )}

            {/* Merge button */}
            {compareBranch && mergeAnalysisForRefData && (
              <div className="flex items-center gap-2 pt-2 border-t">
                <Button
                  size="sm"
                  variant={mergeAnalysisForRefData.supported_strategies.length > 0 ? "default" : "destructive"}
                  disabled={mergeMutation.isPending}
                  onClick={() => {
                    if (mergeAnalysisForRefData.supported_strategies.length > 0) {
                      if (confirm(`Merge "${compareBranch}" into "${currentBranchData?.name?.replace("refs/heads/", "")}"?`)) {
                        mergeMutation.mutate({
                          from: compareBranch,
                          to: currentBranchData?.name?.replace("refs/heads/", "") || "main",
                        });
                      }
                    } else {
                      toast.error("Cannot merge: conflicts exist. Please resolve conflicts first.");
                    }
                  }}
                >
                  {mergeMutation.isPending ? (
                    <Loader2 className="h-4 w-4 animate-spin" />
                  ) : (
                    <>
                      <GitMerge className="h-4 w-4 mr-1" />
                      Merge
                    </>
                  )}
                </Button>
                {mergeAnalysisForRefData.supported_strategies.length === 0 && (
                  <span className="text-xs text-muted-foreground">
                    Resolve conflicts manually before merging
                  </span>
                )}
              </div>
            )}
          </div>
        )}

        <div className="border rounded-md divide-y">
          {filtered.length === 0 ? (
            <div className="p-8 text-center text-muted-foreground">No branches found</div>
          ) : (
            filtered.map((branch) => (
              <div key={branch.name} className="flex items-center justify-between px-4 py-3">
                <div className="flex items-center gap-3">
                  <span className="font-mono text-sm">{branch.name}</span>
                  {branch.is_head && <Badge variant="secondary">HEAD</Badge>}
                </div>
                <div className="flex items-center gap-1">
                  <Button
                    size="sm"
                    variant="ghost"
                    onClick={() => {
                      setRenameBranch(branch.name);
                      setNewBranchName(branch.name.replace("refs/heads/", ""));
                    }}
                    disabled={branch.is_head}
                    title="Rename branch"
                  >
                    <Edit className="h-4 w-4" />
                  </Button>
                  <Button
                    size="sm"
                    variant="ghost"
                    onClick={() => {
                      setMoveBranch(branch.name);
                      setMoveTarget("");
                    }}
                    disabled={branch.is_head}
                    title="Move branch to commit"
                  >
                    <ArrowRight className="h-4 w-4" />
                  </Button>
                  <Button
                    size="sm"
                    variant="ghost"
                    onClick={() => {
                      if (confirm(`Delete remote branch "${branch.name}"?`)) {
                        deleteRemoteMutation.mutate(branch.name);
                      }
                    }}
                    disabled={deleteMutation.isPending}
                    title="Delete remote branch"
                    className="text-orange-500 hover:text-orange-600"
                  >
                    <CloudOff className="h-4 w-4" />
                  </Button>
                  <Button
                    size="sm"
                    variant="ghost"
                    onClick={() => {
                      if (confirm(`Delete local branch "${branch.name}"?`)) {
                        deleteMutation.mutate(branch.name);
                      }
                    }}
                    disabled={deleteMutation.isPending || branch.is_head}
                    className="text-destructive hover:text-destructive"
                  >
                    <Trash2 className="h-4 w-4" />
                  </Button>
                </div>
              </div>
            ))
          )}
        </div>
      </div>
    </>
  );
};
