/**
 * Shared presentational helpers for tickets: human labels, badge styling, and
 * the clickable `#ref` element (F7). Kept pure/presentational so both the list
 * and the detail surfaces render tickets consistently.
 */

import type { ReactNode } from "react";

import type { TicketLinkKind, TicketPriority, TicketStatus } from "@/domain";
import { cn } from "@/shared";

export const TICKET_STATUSES: TicketStatus[] = [
  "open",
  "inProgress",
  "QA",
  "closed",
];

export const TICKET_PRIORITIES: TicketPriority[] = [
  "low",
  "medium",
  "high",
  "critical",
];

export const TICKET_LINK_KINDS: TicketLinkKind[] = [
  "relatesTo",
  "blocks",
  "blockedBy",
  "duplicates",
  "dependsOn",
];

export function statusLabel(status: TicketStatus): string {
  switch (status) {
    case "open":
      return "Open";
    case "inProgress":
      return "In progress";
    case "QA":
      return "QA";
    case "closed":
      return "Closed";
  }
}

export function priorityLabel(priority: TicketPriority): string {
  return priority.charAt(0).toUpperCase() + priority.slice(1);
}

export function linkKindLabel(kind: TicketLinkKind): string {
  switch (kind) {
    case "relatesTo":
      return "relates to";
    case "blocks":
      return "blocks";
    case "blockedBy":
      return "blocked by";
    case "duplicates":
      return "duplicates";
    case "dependsOn":
      return "depends on";
  }
}

function statusClass(status: TicketStatus): string {
  switch (status) {
    case "open":
      return "bg-raised text-muted";
    case "inProgress":
      return "bg-warning/15 text-warning";
    case "QA":
      return "bg-primary/15 text-primary";
    case "closed":
      return "bg-success/15 text-success";
  }
}

function priorityClass(priority: TicketPriority): string {
  switch (priority) {
    case "low":
      return "bg-raised text-muted";
    case "medium":
      return "bg-primary/10 text-primary";
    case "high":
      return "bg-warning/15 text-warning";
    case "critical":
      return "bg-danger/15 text-danger";
  }
}

function badgeBase(className?: string): string {
  return cn(
    "inline-flex shrink-0 items-center rounded-full px-2 py-0.5 text-xs font-medium",
    className,
  );
}

export function StatusBadge({ status }: { status: TicketStatus }) {
  return <span className={badgeBase(statusClass(status))}>{statusLabel(status)}</span>;
}

export function PriorityBadge({ priority }: { priority: TicketPriority }) {
  return (
    <span className={badgeBase(priorityClass(priority))}>
      {priorityLabel(priority)}
    </span>
  );
}

/**
 * A clickable ticket reference badge (`#42`). Renders as a button when
 * `onOpen` is provided (F7 — opens the ticket detail), else as plain text.
 */
export function TicketRef({
  ticketRef,
  onOpen,
  className,
}: {
  ticketRef: string;
  onOpen?: (ref: string) => void;
  className?: string;
}) {
  const base = cn(
    "inline-flex shrink-0 items-center rounded bg-raised px-1.5 py-0.5 font-mono text-xs text-content",
    className,
  );
  if (!onOpen) return <code className={base}>{ticketRef}</code>;
  return (
    <button
      type="button"
      aria-label={`open ticket ${ticketRef}`}
      className={cn(base, "transition-colors hover:bg-primary/15 hover:text-primary")}
      onClick={() => onOpen(ticketRef)}
    >
      {ticketRef}
    </button>
  );
}

const REF_PATTERN = /#\d+/g;

/**
 * Linkifies inline `#42` references inside arbitrary text (F7). Non-ref segments
 * are preserved verbatim; each `#n` becomes a clickable {@link TicketRef} when
 * `onOpen` is provided.
 */
export function linkifyTicketRefs(
  text: string,
  onOpen?: (ref: string) => void,
): ReactNode[] {
  const out: ReactNode[] = [];
  let last = 0;
  let index = 0;
  for (const match of text.matchAll(REF_PATTERN)) {
    const start = match.index ?? 0;
    if (start > last) out.push(text.slice(last, start));
    out.push(
      <TicketRef
        key={`ref-${index++}-${start}`}
        ticketRef={match[0]}
        onOpen={onOpen}
      />,
    );
    last = start + match[0].length;
  }
  if (last < text.length) out.push(text.slice(last));
  return out;
}
