import { useState } from "react";
import { Link, useParams, useNavigate } from "react-router";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { client, type LabelResponse, type MilestoneResponse, type IssueAuthor, type IssueEventResponse } from "@/client";
import { Button } from "@/components/ui/button";
import { Popover, PopoverTrigger, PopoverContent } from "@/components/ui/popover";
import {
  AlertDialog,
  AlertDialogAction,
  AlertDialogCancel,
  AlertDialogContent,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
import { useToast } from "@/hooks/use-toast";
import { useAuth } from "@/context/auth-context";
import { workspaceColor, workspaceInitial } from "@/components/shell/shared";
import CommentSection from "./comment-section";
import EditIssueDialog from "./edit-issue-dialog";
import { LabelManageDialog } from "./label-manage-dialog";
import { MilestoneManageDialog } from "./milestone-manage-dialog";
import {
  Circle,
  CircleDot,
  Clock3,
  GitFork,
  Pencil,
  Trash2,
  Lock,
  LockOpen,
  ChevronRight,
  ExternalLink,
  Plus,
  X,
  Calendar,
  AlertCircle,
} from "lucide-react";

// ─── shared helpers ────────────────────────────────────────

function AuthorAvatar({ author }: { author: { username: string; avatar_url?: string | null; display_name?: string | null } }) {
  const name = author.display_name ?? author.username;
  return (
    <span
      className={cn(
        "grid size-5 shrink-0 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>
  );
}

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

function formatRelative(date: string) {
  const diff = Date.now() - new Date(date).getTime();
  const mins = Math.floor(diff / 60000);
  if (mins < 1) return "just now";
  if (mins < 60) return `${mins}m ago`;
  const hrs = Math.floor(mins / 60);
  if (hrs < 24) return `${hrs}h ago`;
  const days = Math.floor(hrs / 24);
  if (days < 30) return `${days}d ago`;
  return formatDate(date);
}

function formatEventValue(event: string, value: string | null) {
  if (!value) return "";
  if (event === "labeled" || event === "unlabeled") return value;
  if (event === "milestoned" || event === "demilestoned") return value;
  if (event === "assigned" || event === "unassigned") return value;
  if (event === "priority_changed") return value;
  if (event === "closed" || event === "reopened") return "";
  return value;
}

// ─── sidebar section ───────────────────────────────────────

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

// ─── assignee picker ───────────────────────────────────────

function AssigneeSection({
  assignees,
  projectName,
  issueNumber,
  queryKey,
}: {
  assignees: IssueAuthor[];
  projectName: string;
  issueNumber: number;
  queryKey: unknown[];
}) {
  const qc = useQueryClient();
  const { toast } = useToast();
  const [open, setOpen] = useState(false);

  const { data: members = [] } = useQuery({
    queryKey: ["workspace", projectName, "members"],
    queryFn: async () => {
      const res = await client.workspaceListMembers(projectName, { limit: 100 } as any);
      return (res.data ?? []) as Array<{ username: string; display_name?: string | null; avatar_url?: string | null }>;
    },
    retry: false,
  });

  const assignMutation = useMutation({
    mutationFn: async (username: string) => {
      await client.issuesAssignUser(projectName, issueNumber, { username });
    },
    onSuccess: () => { qc.invalidateQueries({ queryKey }); setOpen(false); },
    onError: (e: any) => toast({ title: "Failed to assign", description: String(e?.message ?? e), variant: "destructive" }),
  });

  const unassignMutation = useMutation({
    mutationFn: async (username: string) => {
      await client.issuesUnassignUser(projectName, issueNumber, { data: { username } } as any);
    },
    onSuccess: () => qc.invalidateQueries({ queryKey }),
    onError: (e: any) => toast({ title: "Failed to unassign", description: String(e?.message ?? e), variant: "destructive" }),
  });

  const assignedUsernames = new Set(assignees.map((a) => a.username));

  return (
    <SidebarSection title="Assignees">
      {assignees.length > 0 ? (
        <div className="flex flex-wrap items-center gap-1.5">
          {assignees.map((a) => (
            <span
              key={a.username}
              className="inline-flex items-center gap-1 rounded-full border border-border bg-muted/30 px-2 py-0.5 text-[12px] cursor-pointer hover:border-destructive/30 hover:bg-destructive/5 transition-colors"
              onClick={() => unassignMutation.mutate(a.username)}
            >
              <AuthorAvatar author={a} />
              <span className="max-w-[80px] truncate">{a.display_name ?? a.username}</span>
              <X className="size-2.5 text-muted-foreground" />
            </span>
          ))}
        </div>
      ) : (
        <span className="text-[12px] text-muted-foreground">No one assigned</span>
      )}
      <Popover open={open} onOpenChange={setOpen}>
        <PopoverTrigger asChild>
          <Button className="mt-1.5 h-7 px-2 text-[11px] w-full justify-start" variant="ghost">
            <Plus className="size-3 mr-1" /> Assign someone
          </Button>
        </PopoverTrigger>
        <PopoverContent className="w-48 p-1" align="start">
          <ScrollArea className="max-h-48">
            {members.filter((m) => !assignedUsernames.has(m.username)).map((m) => (
              <button
                key={m.username}
                className="flex w-full items-center gap-2 rounded px-2 py-1.5 text-[12px] text-foreground hover:bg-muted cursor-pointer"
                onClick={() => assignMutation.mutate(m.username)}
              >
                <AuthorAvatar author={m as any} />
                <span className="truncate">{m.display_name ?? m.username}</span>
              </button>
            ))}
            {members.filter((m) => !assignedUsernames.has(m.username)).length === 0 && (
              <p className="px-2 py-2 text-[11px] text-muted-foreground">No one available</p>
            )}
          </ScrollArea>
        </PopoverContent>
      </Popover>
    </SidebarSection>
  );
}

// ─── label sidebar section ─────────────────────────────────

function LabelSection({
  labels,
  projectName,
  issueNumber,
  queryKey,
}: {
  labels: LabelResponse[];
  projectName: string;
  issueNumber: number;
  queryKey: unknown[];
}) {
  const qc = useQueryClient();
  const { toast } = useToast();
  const [pickerOpen, setPickerOpen] = useState(false);
  const [manageOpen, setManageOpen] = useState(false);

  const currentLabelIds = new Set(labels.map((l) => l.id));

  const { data: allLabels = [] } = useQuery({
    queryKey: ["labels", projectName],
    queryFn: async () => {
      const res = await client.issuesListLabels(projectName);
      return res.data ?? [];
    },
    enabled: pickerOpen || manageOpen,
    retry: false,
  });

  const addMutation = useMutation({
    mutationFn: async (labelId: string) => {
      await client.issuesAddIssueLabel(projectName, issueNumber, { label_id: labelId });
    },
    onSuccess: () => { qc.invalidateQueries({ queryKey }); setPickerOpen(false); },
    onError: (e: any) => toast({ title: "Failed", description: String(e?.message ?? e), variant: "destructive" }),
  });

  const removeMutation = useMutation({
    mutationFn: async (labelId: string) => {
      await client.issuesRemoveIssueLabel(projectName, issueNumber, { data: { label_id: labelId } } as any);
    },
    onSuccess: () => qc.invalidateQueries({ queryKey }),
    onError: (e: any) => toast({ title: "Failed", description: String(e?.message ?? e), variant: "destructive" }),
  });

  const availableLabels = allLabels.filter((l) => !currentLabelIds.has(l.id));

  return (
    <SidebarSection title="Labels">
      {labels.length > 0 ? (
        <div className="flex flex-wrap items-center gap-1">
          {labels.map((label) => (
            <span
              key={label.id}
              className="inline-flex h-[18px] cursor-pointer items-center gap-0.5 rounded px-1.5 text-[11px] font-medium leading-none whitespace-nowrap hover:opacity-80 transition-opacity"
              style={{ backgroundColor: label.color + "18", color: label.color }}
              onClick={() => removeMutation.mutate(label.id)}
            >
              {label.name} <X className="size-2.5" />
            </span>
          ))}
        </div>
      ) : (
        <span className="text-[12px] text-muted-foreground">None yet</span>
      )}
      <div className="flex items-center gap-1 mt-1.5">
        <Popover open={pickerOpen} onOpenChange={setPickerOpen}>
          <PopoverTrigger asChild>
            <Button className="h-7 px-2 text-[11px]" variant="ghost">
              <Plus className="size-3 mr-1" /> Add label
            </Button>
          </PopoverTrigger>
          <PopoverContent className="w-52 p-1" align="start">
            <ScrollArea className="max-h-48">
              {availableLabels.length > 0 ? (
                availableLabels.map((l) => (
                  <button
                    key={l.id}
                    className="flex w-full items-center gap-2 rounded px-2 py-1.5 text-[12px] text-foreground hover:bg-muted cursor-pointer"
                    onClick={() => addMutation.mutate(l.id)}
                  >
                    <span className="h-3 w-3 shrink-0 rounded-full" style={{ backgroundColor: l.color }} />
                    <span className="truncate">{l.name}</span>
                  </button>
                ))
              ) : (
                <p className="px-2 py-2 text-[11px] text-muted-foreground">No labels available</p>
              )}
            </ScrollArea>
          </PopoverContent>
        </Popover>
        <Button className="h-7 px-2 text-[11px]" variant="ghost" onClick={() => setManageOpen(true)}>
          <Pencil className="size-3" />
        </Button>
      </div>
      <LabelManageDialog
        open={manageOpen}
        onOpenChange={setManageOpen}
        projectName={projectName}
        onSelect={(label) => {
          if (!currentLabelIds.has(label.id)) addMutation.mutate(label.id);
        }}
      />
    </SidebarSection>
  );
}

// ─── milestone sidebar section ─────────────────────────────

function MilestoneSection({
  milestone,
  projectName,
  issueNumber,
  queryKey,
}: {
  milestone: MilestoneResponse | null | undefined;
  projectName: string;
  issueNumber: number;
  queryKey: unknown[];
}) {
  const qc = useQueryClient();
  const { toast } = useToast();
  const [pickerOpen, setPickerOpen] = useState(false);
  const [manageOpen, setManageOpen] = useState(false);

  const { data: milestones = [] } = useQuery({
    queryKey: ["milestones", projectName],
    queryFn: async () => {
      const res = await client.issuesListMilestones(projectName);
      return res.data ?? [];
    },
    enabled: pickerOpen || manageOpen,
    retry: false,
  });

  const setMutation = useMutation({
    mutationFn: async (milestoneId: string) => {
      await client.issuesSetIssueMilestone(projectName, issueNumber, { milestone_id: milestoneId });
    },
    onSuccess: () => { qc.invalidateQueries({ queryKey }); setPickerOpen(false); },
    onError: (e: any) => toast({ title: "Failed", description: String(e?.message ?? e), variant: "destructive" }),
  });

  const clearMutation = useMutation({
    mutationFn: async () => {
      await client.issuesClearIssueMilestone(projectName, issueNumber);
    },
    onSuccess: () => qc.invalidateQueries({ queryKey }),
    onError: (e: any) => toast({ title: "Failed", description: String(e?.message ?? e), variant: "destructive" }),
  });

  const openMilestones = milestones.filter((m) => m.state === "open");

  return (
    <SidebarSection title="Milestone">
      {milestone ? (
        <div className="space-y-1">
          <div className="flex items-center gap-1.5">
            <span className="text-[12px] font-heading font-medium text-foreground">{milestone.title}</span>
            <button className="text-muted-foreground hover:text-destructive cursor-pointer" onClick={() => clearMutation.mutate()}>
              <X className="size-3" />
            </button>
          </div>
          {milestone.due_at && (
            <span className="font-mono text-[10px] text-muted-foreground">Due {formatDate(milestone.due_at)}</span>
          )}
        </div>
      ) : (
        <span className="text-[12px] text-muted-foreground">No milestone</span>
      )}
      <div className="flex items-center gap-1 mt-1.5">
        <Popover open={pickerOpen} onOpenChange={setPickerOpen}>
          <PopoverTrigger asChild>
            <Button className="h-7 px-2 text-[11px]" variant="ghost">
              <Plus className="size-3 mr-1" /> Set milestone
            </Button>
          </PopoverTrigger>
          <PopoverContent className="w-52 p-1" align="start">
            <ScrollArea className="max-h-48">
              {openMilestones.length > 0 ? (
                openMilestones.map((m) => (
                  <button
                    key={m.id}
                    className="flex w-full items-center gap-2 rounded px-2 py-1.5 text-[12px] text-foreground hover:bg-muted cursor-pointer"
                    onClick={() => setMutation.mutate(m.id)}
                  >
                    <span className="truncate flex-1 text-left">{m.title}</span>
                    {m.due_at && <span className="font-mono text-[10px] text-muted-foreground shrink-0">{new Date(m.due_at).toLocaleDateString()}</span>}
                  </button>
                ))
              ) : (
                <p className="px-2 py-2 text-[11px] text-muted-foreground">No milestones</p>
              )}
            </ScrollArea>
          </PopoverContent>
        </Popover>
        <Button className="h-7 px-2 text-[11px]" variant="ghost" onClick={() => setManageOpen(true)}>
          <Pencil className="size-3" />
        </Button>
      </div>
      <MilestoneManageDialog
        open={manageOpen}
        onOpenChange={setManageOpen}
        projectName={projectName}
        onSelect={(m) => setMutation.mutate(m.id)}
      />
    </SidebarSection>
  );
}

// ─── event timeline ────────────────────────────────────────

function EventTimeline({ projectName, issueNumber }: { projectName: string; issueNumber: number }) {
  const { data: events = [], isLoading } = useQuery({
    queryKey: ["issue", projectName, issueNumber, "events"],
    queryFn: async () => {
      const res = await client.issuesListEvents(projectName, issueNumber);
      return (res.data ?? []) as IssueEventResponse[];
    },
    retry: false,
  });

  if (isLoading) {
    return (
      <div className="mt-5 pt-3 border-t border-border">
        <p className="text-[11px] text-muted-foreground">Loading events...</p>
      </div>
    );
  }

  if (events.length === 0) return null;

  return (
    <div className="mt-5 pt-3 border-t border-border">
      <p className="font-mono text-[10px] uppercase tracking-wider text-muted-foreground mb-2">Timeline</p>
      <div className="space-y-2">
        {events.map((evt, i) => (
          <div key={i} className="flex items-center gap-2 text-[11px] text-muted-foreground">
            {evt.actor ? (
              <span className="flex items-center gap-1">
                <AuthorAvatar author={evt.actor} />
                <span className="font-medium text-foreground">{evt.actor.display_name ?? evt.actor.username}</span>
              </span>
            ) : (
              <AlertCircle className="size-3" />
            )}
            <span className="capitalize">{evt.event.replace(/_/g, " ")}</span>
            {evt.to_value && (
              <>
                <ChevronRight className="size-3" />
                <span className="font-medium text-foreground">{formatEventValue(evt.event, evt.to_value)}</span>
              </>
            )}
            <span className="font-mono text-[10px]">{formatRelative(evt.created_at)}</span>
          </div>
        ))}
      </div>
    </div>
  );
}

// ─── main page ─────────────────────────────────────────────

export default function IssueDetailPage() {
  const { projectName = "", issueNumber } = useParams();
  const navigate = useNavigate();
  const { user } = useAuth();
  const qc = useQueryClient();
  const { toast } = useToast();
  const num = Number(issueNumber);

  const [editOpen, setEditOpen] = useState(false);

  const queryKey = ["issue", projectName, num];

  const { data: issue, isLoading } = useQuery({
    queryKey,
    queryFn: async () => {
      const res = await client.issuesGetIssue(projectName, num);
      return res.data;
    },
    enabled: Boolean(projectName) && num > 0,
    retry: false,
  });

  const closeMutation = useMutation({
    mutationFn: async () => {
      await client.issuesCloseIssue(projectName, num);
    },
    onSuccess: () => qc.invalidateQueries({ queryKey }),
    onError: (e: any) => toast({ title: "Failed to close", description: String(e?.message ?? e), variant: "destructive" }),
  });

  const reopenMutation = useMutation({
    mutationFn: async () => {
      await client.issuesReopenIssue(projectName, num);
    },
    onSuccess: () => qc.invalidateQueries({ queryKey }),
    onError: (e: any) => toast({ title: "Failed to reopen", description: String(e?.message ?? e), variant: "destructive" }),
  });

  const deleteMutation = useMutation({
    mutationFn: async () => {
      await client.issuesDeleteIssue(projectName, num);
    },
    onSuccess: () => {
      qc.invalidateQueries({ queryKey: ["issues", projectName] });
      navigate(`/${projectName}/issues`);
    },
    onError: (e: any) => toast({ title: "Failed to delete", description: String(e?.message ?? e), variant: "destructive" }),
  });

  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 (!issue) {
    return (
      <div className="px-8 py-10 text-center">
        <p className="text-[13px] text-muted-foreground">Issue not found</p>
      </div>
    );
  }

  const isOpen = issue.state === "open";
  const currentUsername = user?.username;

  return (
    <div className="mx-auto max-w-5xl px-8 py-10">
      {/* Header */}
      <div className="flex items-start gap-2 justify-between">
        <div className="flex items-center gap-2 min-w-0">
          {isOpen ? (
            <Circle className="size-4 text-success shrink-0" />
          ) : (
            <CircleDot className="size-4 text-purple-600 shrink-0" />
          )}
          <h1 className="font-heading text-[15px] font-bold text-foreground truncate">{issue.title}</h1>
          <span className="font-mono text-[12px] text-muted-foreground/60 shrink-0"># {issue.number}</span>
        </div>

        {/* action buttons */}
        <div className="flex items-center gap-1.5 shrink-0">
          {isOpen ? (
            <Button className="h-8 px-3 text-[12px]" variant="outline" onClick={() => closeMutation.mutate()}>
              <Lock className="size-3.5 mr-1" />
              Close issue
            </Button>
          ) : (
            <Button className="h-8 px-3 text-[12px]" variant="outline" onClick={() => reopenMutation.mutate()}>
              <LockOpen className="size-3.5 mr-1" />
              Reopen issue
            </Button>
          )}
          <Button className="h-8 px-3 text-[12px]" variant="outline" onClick={() => setEditOpen(true)}>
            <Pencil className="size-3.5 mr-1" />
            Edit
          </Button>
          <AlertDialog>
            <AlertDialogTrigger asChild>
              <Button className="h-8 px-2 text-[12px] text-destructive hover:bg-destructive/10" variant="ghost">
                <Trash2 className="size-3.5" />
              </Button>
            </AlertDialogTrigger>
            <AlertDialogContent>
              <AlertDialogHeader>
                <AlertDialogTitle>Delete &ldquo;{issue.title}&rdquo;?</AlertDialogTitle>
                <AlertDialogDescription>This action cannot be undone.</AlertDialogDescription>
              </AlertDialogHeader>
              <AlertDialogFooter>
                <AlertDialogCancel>Cancel</AlertDialogCancel>
                <AlertDialogAction onClick={() => deleteMutation.mutate()}>Delete</AlertDialogAction>
              </AlertDialogFooter>
            </AlertDialogContent>
          </AlertDialog>
        </div>
      </div>

      {/* meta row */}
      <div className="mt-1 flex items-center gap-2 text-[12px] text-muted-foreground">
        <span className="flex items-center gap-1">
          <AuthorAvatar author={issue.author} />
          <span className="font-medium text-foreground">{issue.author.display_name ?? issue.author.username}</span>
        </span>
        <span>
          {isOpen ? "opened" : "closed"} {formatRelative(issue.created_at)}
        </span>
        {issue.closed_at && (
          <span className="flex items-center gap-1"><Clock3 className="size-3" />Closed {formatRelative(issue.closed_at)}</span>
        )}
        {issue.priority && (
          <span className={cn(
            "font-mono text-[10px] uppercase px-1.5 py-0.5 rounded",
            issue.priority === "critical" ? "bg-destructive/10 text-destructive dark:bg-destructive/20 dark:text-destructive" :
            issue.priority === "high" ? "bg-orange-100 text-orange-700 dark:bg-orange-900/30 dark:text-orange-400" :
            issue.priority === "low" ? "bg-slate-100 text-slate-600 dark:bg-slate-800 dark:text-slate-400" :
            "bg-info/10 text-info dark:bg-info/20 dark:text-info",
          )}>
            {issue.priority}
          </span>
        )}
        {issue.due_at && (
          <span className="flex items-center gap-1">
            <Calendar className="size-3" />
            Due {formatDate(issue.due_at)}
          </span>
        )}
      </div>

      {/* Body: two-column layout */}
      <div className="mt-5 grid grid-cols-[1fr_240px] gap-6">
        {/* Main content */}
        <div>
          {issue.labels.length > 0 && (
            <div className="flex items-center gap-1.5 mb-3">
              {issue.labels.map((label) => (
                <LabelBadge key={label.id} label={label} />
              ))}
            </div>
          )}

          {issue.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={issue.author} />
                <span className="font-heading text-[13px] font-medium text-foreground">{issue.author.display_name ?? issue.author.username}</span>
                <span className="font-mono text-[11px] text-muted-foreground">commented {formatRelative(issue.created_at)}</span>
              </div>
              <div className="px-4 py-3 text-[13px] text-foreground whitespace-pre-wrap leading-relaxed">
                {issue.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>
          )}

          {/* Linked pull requests */}
          {issue.pull_requests.length > 0 && (
            <div className="mt-5">
              <p className="font-mono text-[10px] uppercase tracking-wider text-muted-foreground mb-2">Linked pull requests</p>
              <div className="space-y-1.5">
                {issue.pull_requests.map((pr) => (
                  <Link
                    key={pr.id}
                    to={`/${projectName}/repos/${pr.title}/pulls/${pr.number}`}
                    className="flex items-center gap-2 rounded-md border border-border px-3 py-2 hover:bg-muted/50 transition-colors cursor-pointer"
                  >
                    <GitFork className="size-3.5 text-muted-foreground shrink-0" />
                    <span className="font-heading text-[13px] font-medium text-foreground truncate">{pr.title}</span>
                    <span className="font-mono text-[11px] text-muted-foreground shrink-0"># {pr.number}</span>
                    <span className={cn("font-mono text-[10px] shrink-0", pr.state === "open" ? "text-success" : "text-purple-600")}>
                      {pr.state}
                    </span>
                    <ExternalLink className="size-3 text-muted-foreground shrink-0" />
                  </Link>
                ))}
              </div>
            </div>
          )}

          {/* Linked repos */}
          {issue.repos.length > 0 && (
            <div className="mt-5">
              <p className="font-mono text-[10px] uppercase tracking-wider text-muted-foreground mb-2">Linked repositories</p>
              <div className="space-y-1.5">
                {issue.repos.map((repo) => (
                  <Link
                    key={repo.id}
                    to={`/${projectName}/repos/${repo.name}`}
                    className="flex items-center gap-2 rounded-md border border-border px-3 py-2 hover:bg-muted/50 transition-colors cursor-pointer"
                  >
                    <GitFork className="size-3.5 text-muted-foreground shrink-0" />
                    <span className="font-heading text-[13px] font-medium text-foreground">{repo.name}</span>
                    <ExternalLink className="size-3 text-muted-foreground shrink-0 ml-auto" />
                  </Link>
                ))}
              </div>
            </div>
          )}

          {/* Comments section */}
          <CommentSection
            projectName={projectName}
            issueNumber={num}
            currentUsername={currentUsername}
            queryKey={queryKey}
          />

          {/* Event Timeline */}
          <EventTimeline projectName={projectName} issueNumber={num} />
        </div>

        {/* Sidebar */}
        <div className="rounded-md border border-border overflow-hidden">
          <AssigneeSection
            assignees={issue.assignees}
            projectName={projectName}
            issueNumber={num}
            queryKey={queryKey}
          />

          <LabelSection
            labels={issue.labels}
            projectName={projectName}
            issueNumber={num}
            queryKey={queryKey}
          />

          <MilestoneSection
            milestone={issue.milestone}
            projectName={projectName}
            issueNumber={num}
            queryKey={queryKey}
          />

          <SidebarSection title="Priority">
            <span className={cn(
              "text-[12px] font-heading font-medium capitalize",
              issue.priority === "critical" ? "text-destructive" :
              issue.priority === "high" ? "text-orange-600" :
              issue.priority === "low" ? "text-muted-foreground" :
              "text-foreground",
            )}>
              {issue.priority ?? "None"}
            </span>
          </SidebarSection>

          {issue.due_at && (
            <SidebarSection title="Due date">
              <span className="text-[12px] text-foreground">{formatDate(issue.due_at)}</span>
            </SidebarSection>
          )}
        </div>
      </div>

      {/* Edit dialog */}
      <EditIssueDialog
        open={editOpen}
        onOpenChange={setEditOpen}
        issue={issue}
        projectName={projectName}
        queryKey={queryKey}
      />
    </div>
  );
}
