"use client";

import { useMemo, useState } from "react";

import {
  type ColumnDef,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table";
import { CircleDot, ExternalLink, XCircle } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { DataTable } from "@/components/tables/DataTable";
import type { ForgejoIssue, ForgejoIssueLabel } from "@/lib/api-forgejo";
import type { ForgejoRepository } from "@/lib/api-forgejo";
import { CloseForgejoIssueDialog } from "@/components/git/CloseForgejoIssueDialog";

/** Normalize a Forgejo label color to a valid 6-char hex string or null. */
function normalizeLabelColor(raw: string | null | undefined): string | null {
  if (!raw) return null;
  const hex = raw.replace(/^#+/, "");
  return /^[0-9a-fA-F]{3,6}$/.test(hex) ? `#${hex.padEnd(6, "0")}` : null;
}

/** Return white or dark text based on WCAG relative luminance of a hex background. */
function labelTextColor(hex: string): string {
  const h = hex.replace("#", "");
  const r = parseInt(h.slice(0, 2), 16) / 255;
  const g = parseInt(h.slice(2, 4), 16) / 255;
  const b = parseInt(h.slice(4, 6), 16) / 255;
  const lin = (c: number) =>
    c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);
  const L = 0.2126 * lin(r) + 0.7152 * lin(g) + 0.0722 * lin(b);
  return L > 0.179 ? "#1a1a1a" : "#ffffff";
}

function LabelChip({ label }: { label: ForgejoIssueLabel }) {
  const bg = normalizeLabelColor(label.color);
  return (
    <Badge
      variant="outline"
      className="shrink-0 text-xs"
      style={
        bg
          ? { backgroundColor: bg, color: labelTextColor(bg), borderColor: bg }
          : undefined
      }
      title={label.description ?? label.name}
    >
      {label.name}
    </Badge>
  );
}

export type ForgejoIssuesTableProps = {
  issues: ForgejoIssue[];
  repositories: ForgejoRepository[];
  isLoading?: boolean;
  canClose?: boolean;
  onRefresh: () => void;
};

export function ForgejoIssuesTable({
  issues,
  repositories,
  isLoading = false,
  canClose = false,
  onRefresh,
}: ForgejoIssuesTableProps) {
  const [issueToClose, setIssueToClose] = useState<ForgejoIssue | null>(null);
  const [isCloseDialogOpen, setIsCloseDialogOpen] = useState(false);

  const repositoryNameById = useMemo(() => {
    const map = new Map<string, string>();
    for (const repository of repositories) {
      map.set(
        repository.id,
        repository.display_name || `${repository.owner}/${repository.repo}`,
      );
    }
    return map;
  }, [repositories]);
  const columns: ColumnDef<ForgejoIssue>[] = useMemo(
    () => [
      {
        id: "repository",
        header: "Repository",
        cell: ({ row }) => {
          const fallback = row.original.repository_id;
          return (
            <span className="block max-w-[220px] truncate text-muted">
              {repositoryNameById.get(row.original.repository_id) ?? fallback}
            </span>
          );
        },
      },
      {
        accessorKey: "forgejo_issue_number",
        header: "#",
        cell: ({ row }) => (
          <a
            href={row.original.html_url}
            target="_blank"
            rel="noopener noreferrer"
            className="inline-flex items-center gap-1 font-mono text-sm text-[color:var(--accent)] hover:underline"
          >
            #{row.original.forgejo_issue_number}
            <ExternalLink className="h-3 w-3" />
          </a>
        ),
      },
      {
        accessorKey: "title",
        header: "Title",
        cell: ({ row }) => (
          <div
            className="max-w-[28rem] truncate font-medium text-strong"
            title={row.original.title}
          >
            {row.original.title}
          </div>
        ),
      },
      {
        accessorKey: "state",
        header: "State",
        cell: ({ row }) => {
          const state = row.original.state;
          return (
            <Badge variant={state === "open" ? "success" : "default"}>
              {state}
            </Badge>
          );
        },
      },
      {
        accessorKey: "labels",
        header: "Labels",
        cell: ({ row }) => {
          const labels = row.original.labels;
          if (!labels || labels.length === 0) return null;
          const visible = labels.slice(0, 3);
          const overflow = labels.length - visible.length;
          return (
            <div className="flex max-w-[240px] flex-wrap gap-1">
              {visible.map((label, i) => (
                <LabelChip key={i} label={label} />
              ))}
              {overflow > 0 && (
                <span className="self-center text-xs text-muted">
                  +{overflow}
                </span>
              )}
            </div>
          );
        },
      },
      {
        id: "assignee",
        header: "Assignee",
        cell: ({ row }) => {
          const assignee = row.original.assignees?.[0];
          const login =
            assignee &&
            typeof assignee === "object" &&
            "login" in assignee &&
            typeof assignee.login === "string"
              ? assignee.login
              : null;

          return (
            <span className="block max-w-[160px] truncate text-muted">
              {login || "Unassigned"}
            </span>
          );
        },
      },
      {
        accessorKey: "forgejo_updated_at",
        header: "Updated",
        cell: ({ row }) => {
          try {
            return (
              <span className="whitespace-nowrap text-muted">
                {new Date(row.original.forgejo_updated_at).toLocaleDateString()}
              </span>
            );
          } catch {
            return (
              <span className="text-muted">
                {row.original.forgejo_updated_at}
              </span>
            );
          }
        },
      },
      {
        id: "actions",
        header: "Actions",
        cell: ({ row }) => {
          const issue = row.original;
          const canShowClose =
            canClose && issue.state === "open" && !issue.is_pull_request;
          if (!canShowClose) {
            return null;
          }
          const repositoryName =
            repositoryNameById.get(issue.repository_id) ?? issue.repository_id;
          return (
            <Button
              type="button"
              variant="ghost"
              size="sm"
              className="h-8 w-8 p-0 text-[color:var(--danger)] hover:bg-[color:rgba(248,113,113,0.08)]"
              title={`Close ${repositoryName}#${issue.forgejo_issue_number}`}
              onClick={() => {
                setIssueToClose(issue);
                setIsCloseDialogOpen(true);
              }}
            >
              <XCircle className="h-4 w-4" />
            </Button>
          );
        },
      },
    ],
    [canClose, repositoryNameById],
  );
  const table = useReactTable({
    data: issues,
    columns,
    getCoreRowModel: getCoreRowModel(),
  });

  return (
    <>
      <div className="overflow-hidden rounded-xl border border-[color:var(--border)] bg-[color:var(--surface)] shadow-lush">
        <DataTable
          table={table}
          isLoading={isLoading}
          loadingLabel="Loading Git Project issues…"
          tableClassName="min-w-[980px] w-full text-left text-sm"
          emptyState={{
            icon: <CircleDot className="h-12 w-12" />,
            title: "No Git Project issues found",
            description:
              "Sync a repository to pull issues into Pipeline, or adjust your filters.",
          }}
        />
      </div>
      <CloseForgejoIssueDialog
        issue={issueToClose}
        repositoryName={
          issueToClose
            ? (repositoryNameById.get(issueToClose.repository_id) ??
              issueToClose.repository_id)
            : "Repository"
        }
        open={isCloseDialogOpen}
        onOpenChange={(nextOpen) => {
          setIsCloseDialogOpen(nextOpen);
          if (!nextOpen) {
            setIssueToClose(null);
          }
        }}
        onCloseSuccess={onRefresh}
      />
    </>
  );
}
