import { useState } from "react";
import { useParams, Link } from "react-router";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { client } from "@/client";
import {
  Circle,
  CircleDot,
  GitMerge,
  GitPullRequest,
  MessageSquare,
  Plus,
  Minus,
  FileCode,
  ArrowRight,
  ArrowLeft,
  X,
} from "lucide-react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import { cn } from "@/lib/utils";
import { workspaceColor, workspaceInitial } from "@/components/shell/shared";

function formatDate(date: string) {
  return new Date(date).toLocaleDateString("en-US", { month: "short", day: "numeric", year: "numeric" });
}

function AuthorAvatar({ author }: { author: { username: string; display_name?: string | null; avatar_url?: string | null } }) {
  const name = author.display_name ?? author.username;
  return (
    <span
      className={cn("grid size-6 place-items-center overflow-hidden rounded-full bg-gradient-to-br text-[10px] font-bold text-white", workspaceColor(name))}
    >
      {author.avatar_url ? <img alt="" className="size-full object-cover" src={author.avatar_url} /> : workspaceInitial(name)}
    </span>
  );
}

function LabelBadge({ label }: { label: { name: string; color: string } }) {
  return (
    <span
      className="inline-flex h-[18px] items-center rounded px-1.5 text-[11px] font-medium leading-none whitespace-nowrap"
      style={{ backgroundColor: label.color + "18", color: label.color }}
    >
      {label.name}
    </span>
  );
}

export default function PullDetailPage() {
  const { projectName = "", repoName = "", number = "" } = useParams();
  const prNumber = Number(number);
  const qc = useQueryClient();
  const [showCommentInput, setShowCommentInput] = useState(false);
  const [commentBody, setCommentBody] = useState("");
  const [editing, setEditing] = useState(false);
  const [editTitle, setEditTitle] = useState("");
  const [editBody, setEditBody] = useState("");
  const [assignUsername, setAssignUsername] = useState("");
  const [addLabelName, setAddLabelName] = useState("");
  const [editDraft, setEditDraft] = useState(false);

  const { data: pr, isLoading } = useQuery({
    queryKey: ["repo", projectName, repoName, "pulls", prNumber],
    queryFn: async () => {
      const res = await client.pullRequestGetPr(projectName, repoName, prNumber);
      return res.data;
    },
    enabled: Boolean(projectName) && Boolean(repoName) && prNumber > 0,
    retry: false,
  });

  // Diff between source and target
  const { data: diffData } = useQuery({
    queryKey: ["repo", projectName, repoName, "pr-diff", prNumber],
    queryFn: async () => {
      if (!pr) return null;
      const res = await client.gitDiff(projectName, repoName, { old_oid: pr.target_sha, new_oid: pr.source_sha });
      return res.data;
    },
    enabled: Boolean(pr?.source_sha && pr?.target_sha),
    retry: false,
  });

  const { data: comments = [] } = useQuery({
    queryKey: ["repo", projectName, repoName, "pulls", prNumber, "comments"],
    queryFn: async () => {
      const res = await client.pullRequestListComments(projectName, repoName, prNumber);
      return res.data;
    },
    enabled: prNumber > 0,
    retry: false,
  });

  const closePr = useMutation({
    mutationFn: () => (client as any).pullRequestMergePr(projectName, repoName, prNumber),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }),
  });

  const reopenPr = useMutation({
    mutationFn: () => (client as any).pullRequestUpdatePr(projectName, repoName, prNumber),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }),
  });

  const mergePr = useMutation({
    mutationFn: () => client.pullRequestMergePr(projectName, repoName, prNumber, { method: "merge" }),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }),
  });

  const { data: mergeAnalysis } = useQuery({
    queryKey: ["repo", projectName, repoName, "pulls", prNumber, "merge-analysis"],
    queryFn: async () => {
      const res: any = await client.pullRequestMergeAnalysis(projectName, repoName, prNumber);
      return res.data as { mergeable: boolean };
    },
    enabled: prNumber > 0,
    retry: false,
  });

  const updateBranch = useMutation({
    mutationFn: () => client.pullRequestUpdateBranch(projectName, repoName, prNumber),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }),
  });

  const updatePr = useMutation({
    mutationFn: () => client.pullRequestUpdatePr(projectName, repoName, prNumber, { title: editTitle, body: editBody || null, draft: editDraft || null }),
    onSuccess: () => { setEditing(false); qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }); },
  });

  const assignUser = useMutation({
    mutationFn: () => client.pullRequestAssignUser(projectName, repoName, prNumber, { username: assignUsername }),
    onSuccess: () => { setAssignUsername(""); qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }); },
  });

  const unassignUser = useMutation({
    mutationFn: () => client.pullRequestUnassignUser(projectName, repoName, prNumber),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }),
  });

  const addLabel = useMutation({
    mutationFn: () => client.pullRequestAddLabel(projectName, repoName, prNumber, { name: addLabelName } as any),
    onSuccess: () => { setAddLabelName(""); qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }); },
  });

  const removeLabel = useMutation({
    mutationFn: (name: string) => client.pullRequestRemoveLabel(projectName, repoName, prNumber, { name } as any),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls"] }),
  });

  const addComment = useMutation({
    mutationFn: () => client.pullRequestCreateComment(projectName, repoName, prNumber, { body: commentBody }),
    onSuccess: () => {
      setCommentBody("");
      setShowCommentInput(false);
      qc.invalidateQueries({ queryKey: ["repo", projectName, repoName, "pulls", prNumber, "comments"] });
    },
  });

  if (isLoading) {
    return (
      <div className="px-8 py-10 space-y-3">
        <div className="h-7 animate-pulse rounded bg-muted/50 w-64" />
        <div className="h-24 animate-pulse rounded bg-muted/50" />
      </div>
    );
  }

  if (!pr) {
    return (
      <div className="px-8 py-10 text-center">
        <GitPullRequest className="mx-auto size-5 text-muted-foreground/20" />
        <p className="mt-3 text-[13px] text-muted-foreground">Pull request not found</p>
      </div>
    );
  }

  const isOpen = pr.state === "open" && !pr.merged_at;

  return (
    <div className="mx-auto max-w-5xl px-8 py-10">
      {/* Back link */}
      <Link className="inline-flex items-center gap-1 text-[12px] text-muted-foreground hover:text-foreground transition-colors mb-4" to={`/${projectName}/repo/${repoName}`}>
        <ArrowLeft className="size-3.5" />
        Back to repository
      </Link>

      {/* Header */}
      <div className="flex items-center gap-2">
        {pr.merged_at ? (
          <GitMerge className="size-5 text-purple-600 shrink-0" />
        ) : isOpen ? (
          <Circle className="size-5 text-success shrink-0" />
        ) : (
          <CircleDot className="size-5 text-destructive shrink-0" />
        )}
        <h1 className="font-heading text-[15px] font-bold text-foreground">{pr.title}</h1>
        <span className="font-mono text-[12px] text-muted-foreground/60"># {pr.number}</span>
      </div>

      <div className="mt-2 flex items-center gap-2 text-[12px] text-muted-foreground flex-wrap">
        <AuthorAvatar author={pr.author} />
        <span className="font-medium text-foreground">{pr.author.display_name ?? pr.author.username}</span>
        <span>{pr.merged_at ? "merged" : pr.state === "closed" ? "closed" : "opened"} {formatDate(pr.created_at)}</span>
        {pr.draft && <span className="rounded-md border border-border bg-muted/30 px-2 py-0.5 text-[11px] font-medium text-muted-foreground">Draft</span>}
        <span className="font-mono text-[11px] text-muted-foreground/60">{pr.source_branch} → {pr.target_branch}</span>
      </div>

      {/* Action buttons */}
      {isOpen && (
        <div className="mt-3 flex items-center gap-2">
          {mergeAnalysis && (
            <span className="font-mono text-[11px] text-muted-foreground mr-1">
              {mergeAnalysis.mergeable ? "Mergeable" : "Merge conflicts"}
            </span>
          )}
          <Button className="h-8 px-3 text-[12px]" disabled={mergePr.isPending} onClick={() => mergePr.mutate()}>
            <GitMerge className="size-3.5 mr-1" /> Merge
          </Button>
          <Button className="h-8 px-3 text-[12px]" disabled={updateBranch.isPending} onClick={() => updateBranch.mutate()} variant="outline">
            Update branch
          </Button>
          <Button className="h-8 px-3 text-[12px]" disabled={closePr.isPending} onClick={() => closePr.mutate()} variant="outline">
            <X className="size-3.5 mr-1" /> Close
          </Button>
          <Button className="h-8 px-3 text-[12px]" onClick={() => { setEditing(true); setEditTitle(pr.title); setEditBody(pr.body ?? ""); setEditDraft(pr.draft); }} variant="outline">
            {editing ? "Cancel" : "Edit"}
          </Button>
        </div>
      )}
      {pr.state === "closed" && !pr.merged_at && (
        <div className="mt-3">
          <Button className="h-8 px-3 text-[12px]" onClick={() => reopenPr.mutate()}>
            Reopen
          </Button>
        </div>
      )}

      {/* Edit PR form */}
      {editing && (
        <div className="mt-4 rounded-md border border-border p-4 space-y-3">
          <Input className="h-9 text-[14px] font-heading font-semibold" value={editTitle} onChange={(e) => setEditTitle(e.target.value)} placeholder="Title" />
          <Textarea className="min-h-[120px] text-[13px]" value={editBody} onChange={(e) => setEditBody(e.target.value)} placeholder="Body" />
          <label className="flex items-center gap-2 cursor-pointer">
            <input checked={editDraft} className="size-3.5 rounded border-border accent-primary" onChange={(e) => setEditDraft(e.target.checked)} type="checkbox" />
            <span className="text-[13px] text-foreground">Draft</span>
          </label>
          <div className="flex gap-2">
            <Button className="h-8 px-3 text-[12px]" disabled={!editTitle.trim() || updatePr.isPending} onClick={() => updatePr.mutate()}>Save</Button>
            <Button className="h-8 px-3 text-[12px]" onClick={() => setEditing(false)} variant="outline">Cancel</Button>
          </div>
        </div>
      )}

      <div className="mt-6 grid grid-cols-[1fr_220px] gap-6">
        {/* Main */}
        <div className="space-y-5">
          {/* Labels */}
          {pr.labels.length > 0 && (
            <div className="flex items-center gap-1.5">{pr.labels.map((l) => <LabelBadge key={l.id} label={l} />)}</div>
          )}

          {/* Body */}
          {pr.body ? (
            <div className="rounded-md border border-border overflow-hidden">
              <div className="flex items-center gap-2 bg-muted/30 px-4 py-2 border-b border-border">
                <AuthorAvatar author={pr.author} />
                <span className="font-heading text-[13px] font-medium text-foreground">{pr.author.display_name ?? pr.author.username}</span>
                <span className="font-mono text-[11px] text-muted-foreground ml-auto">{formatDate(pr.created_at)}</span>
              </div>
              <div className="px-4 py-3 text-[13px] text-foreground whitespace-pre-wrap leading-relaxed">{pr.body}</div>
            </div>
          ) : (
            <div className="rounded-md border border-border px-4 py-6 text-center text-[12px] text-muted-foreground">No description provided.</div>
          )}

          {/* Diff stats */}
          {(diffData as any)?.stats && (
            <div>
              <p className="font-mono text-[10px] uppercase tracking-wider text-muted-foreground mb-2">Files changed</p>
              <div className="flex items-center gap-4 text-[12px] mb-3">
                <span className="font-mono text-muted-foreground">{ (diffData as any).stats.files_changed} files</span>
                <span className="flex items-center gap-1 text-success font-mono"><Plus className="size-3" />{ (diffData as any).stats.insertions}</span>
                <span className="flex items-center gap-1 text-destructive font-mono"><Minus className="size-3" />{ (diffData as any).stats.deletions}</span>
              </div>
              <div className="space-y-2">
                {(diffData as any).deltas.map((delta: any, i: number) => {
                  const path = delta.new_file?.path ?? delta.old_file?.path ?? "unknown";
                  return (
                    <div className="rounded-md border border-border overflow-hidden" key={i}>
                      <div className="flex items-center gap-2 bg-muted/30 px-3 py-1.5 border-b border-border">
                        <FileCode className="size-3.5 text-muted-foreground shrink-0" />
                        <span className="font-heading text-[12px] font-medium text-foreground truncate">{path}</span>
                      </div>
                      {delta.lines.length > 0 && (
                        <div className="overflow-auto max-h-[300px]">
                          <table className="w-full font-mono text-[11px] leading-relaxed">
                            <tbody>
                              {delta.lines.map((line: any, j: number) => (
                                <tr className={cn(line.origin === "+" && "bg-success/10", line.origin === "-" && "bg-destructive/10")} key={j}>
                                  <td className="w-10 text-right px-1.5 text-muted-foreground/40 select-none border-r border-border">{line.old_lineno ?? ""}</td>
                                  <td className="w-10 text-right px-1.5 text-muted-foreground/40 select-none border-r border-border">{line.new_lineno ?? ""}</td>
                                  <td className="w-3 text-center text-muted-foreground/50 select-none">{line.origin}</td>
                                  <td className={cn("px-2 whitespace-pre", line.origin === "+" ? "text-success" : line.origin === "-" ? "text-destructive" : "text-foreground")}>{line.content}</td>
                                </tr>
                              ))}
                            </tbody>
                          </table>
                        </div>
                      )}
                    </div>
                  );
                })}
              </div>
            </div>
          )}

          {/* Comments */}
          <div>
            <p className="font-mono text-[10px] uppercase tracking-wider text-muted-foreground mb-2">
              {comments.length > 0 ? `${comments.length} comment${comments.length > 1 ? "s" : ""}` : "Comments"}
            </p>
            <div className="space-y-3">
              {comments.map((c) => (
                <div className="rounded-md border border-border overflow-hidden" key={c.id}>
                  <div className="flex items-center gap-2 bg-muted/30 px-3 py-1.5 border-b border-border">
                    <AuthorAvatar author={c.author} />
                    <span className="font-heading text-[12px] font-medium text-foreground">{c.author.display_name ?? c.author.username}</span>
                    <span className="font-mono text-[11px] text-muted-foreground ml-auto">{formatDate(c.created_at)}</span>
                  </div>
                  <div className="px-3 py-2 text-[13px] text-foreground whitespace-pre-wrap">{c.body}</div>
                </div>
              ))}
            </div>
            {showCommentInput ? (
              <div className="mt-3 space-y-2">
                <Textarea
                  className="min-h-[100px] text-[13px]"
                  placeholder="Leave a comment..."
                  value={commentBody}
                  onChange={(e) => setCommentBody(e.target.value)}
                />
                <div className="flex items-center gap-2">
                  <Button className="h-8 px-3 text-[12px]" disabled={!commentBody.trim()} onClick={() => addComment.mutate()}>Comment</Button>
                  <Button className="h-8 px-3 text-[12px]" onClick={() => { setShowCommentInput(false); setCommentBody(""); }} variant="outline">Cancel</Button>
                </div>
              </div>
            ) : (
              <Button className="mt-3 h-8 px-3 text-[12px]" onClick={() => setShowCommentInput(true)} variant="outline">
                <MessageSquare className="size-3.5 mr-1" /> Leave a comment
              </Button>
            )}
          </div>
        </div>

        {/* Sidebar */}
        <div className="rounded-md border border-border overflow-hidden">
          <SidebarSection title="Status">
            {pr.merged_at ? (
              <span className="text-[12px] text-purple-600 font-heading font-medium">Merged</span>
            ) : pr.state === "open" ? (
              <span className="text-[12px] text-success font-heading font-medium">Open</span>
            ) : (
              <span className="text-[12px] text-destructive font-heading font-medium">Closed</span>
            )}
          </SidebarSection>

          <SidebarSection title="Assignees">
            {pr.assignees.length > 0 ? pr.assignees.map((a) => (
              <div className="flex items-center gap-1.5" key={a.username}>
                <AuthorAvatar author={a} />
                <span className="text-[12px] text-foreground">{a.display_name ?? a.username}</span>
                <button className="ml-auto text-[10px] text-muted-foreground hover:text-destructive" onClick={() => unassignUser.mutate()}>&times;</button>
              </div>
            )) : <span className="text-[12px] text-muted-foreground">No one assigned</span>}
            <div className="mt-1.5 flex items-center gap-1">
              <Input className="h-6 w-full text-[11px]" placeholder="Username" value={assignUsername} onChange={(e) => setAssignUsername(e.target.value)} />
              <Button className="h-6 px-2 text-[10px]" disabled={!assignUsername.trim()} onClick={() => assignUser.mutate()} variant="outline">Add</Button>
            </div>
          </SidebarSection>

          <SidebarSection title="Labels">
            {pr.labels.length > 0 ? pr.labels.map((l) => (
              <div className="flex items-center gap-1.5" key={l.id}>
                <span className="inline-flex h-[18px] items-center rounded px-1.5 text-[11px] font-medium" style={{ backgroundColor: l.color + "18", color: l.color }}>{l.name}</span>
                <button className="ml-auto text-[10px] text-muted-foreground hover:text-destructive" onClick={() => removeLabel.mutate(l.name)}>&times;</button>
              </div>
            )) : <span className="text-[12px] text-muted-foreground">No labels</span>}
            <div className="mt-1.5 flex items-center gap-1">
              <Input className="h-6 w-full text-[11px]" placeholder="Label name" value={addLabelName} onChange={(e) => setAddLabelName(e.target.value)} />
              <Button className="h-6 px-2 text-[10px]" disabled={!addLabelName.trim()} onClick={() => addLabel.mutate()} variant="outline">Add</Button>
            </div>
          </SidebarSection>

          <SidebarSection title="Branches">
            <div className="flex items-center gap-1 text-[12px]">
              <code className="font-mono text-primary">{pr.source_branch}</code>
              <ArrowRight className="size-3 text-muted-foreground" />
              <code className="font-mono text-foreground">{pr.target_branch}</code>
            </div>
          </SidebarSection>
        </div>
      </div>
    </div>
  );
}

function SidebarSection({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <div className="border-b border-border last:border-b-0 py-3 px-3">
      <p className="font-mono text-[10px] uppercase tracking-wider text-muted-foreground mb-1.5">{title}</p>
      {children}
    </div>
  );
}