/**
 * A named record, one click from wherever it was named.
 *
 * Extracted from the approval card, where it was the escape hatch on a pending
 * write: before deciding, open the account and check the note is not already
 * there. It is here because Piggy's answers need the same thing and do not have
 * it — an answer naming "DEMO — 128× H100 reserved, 6 months" and "$399,972.42"
 * is inert text, while the Overview renders that same record as a row with
 * "Match →". Closing that gap is what turns the transcript from an island that
 * knows your data into a surface you can act from.
 *
 * Two honesty rules, both load-bearing:
 *
 *   The title never promises a record the link cannot open. `/accounts/:id` is
 *   the only per-record route PIG has, so everything else lands on the list
 *   that contains the row. "Open the list containing Northwind Robotics" is a
 *   worse sentence than "Open Northwind Robotics" and a true one.
 *
 *   A record with no route renders as plain text rather than as a dead link.
 *   Losing the name would be worse — an answer would silently stop mentioning
 *   the thing it reasoned about — and a chip that goes nowhere is the failure
 *   `tool.tsx` already names: proving nothing is worse than claiming nothing.
 *
 * `newTab` exists because the approval card's own escape hatch was destroying
 * the proposal it existed to help verify: a same-tab navigation unmounts the
 * transcript, and the pending card with it.
 */
import { ArrowUpRight } from 'lucide-react';
import { Link } from 'react-router-dom';
import { cn } from '@/components/ui';

/**
 * Where a record of each kind can be opened.
 *
 * When the other detail routes land, each of these becomes a one-line edit and
 * `opensRecord` grows an entry; this is the only place a record id becomes a
 * URL. The keys are wider than `PiggyRecordType` on purpose — a proposed change
 * carries `record.type` as free text, and `allocation` and `task` are both
 * things a write tool can produce.
 */
export const RECORD_ROUTES: Record<string, string> = {
  account: '/accounts',
  contact: '/accounts',
  demand_deal: '/demand',
  supply_deal: '/supply',
  contract: '/contracts',
  commitment: '/capacity',
  allocation: '/capacity',
  task: '/calendar',
};

/** The URL for a record, or null when PIG has nowhere to send the reader. */
export function recordHref(type: string, id: string): string | null {
  const base = RECORD_ROUTES[type];
  if (!base) return null;
  return type === 'account' ? `${base}/${id}` : base;
}

/** Whether the link opens the record itself or merely the list holding it. */
export function opensRecord(type: string): boolean {
  return type === 'account';
}

export interface RecordLinkProps {
  /** Record type as the payload reported it — free text, not a closed union. */
  type: string;
  id: string;
  /** The record's name. Falls back to a neutral noun rather than showing a uuid. */
  label?: string;
  /**
   * Open in a new tab. Off by default: this is the extracted behaviour, and a
   * link inside a page that steals the tab is normal. Turn it on where leaving
   * would destroy unsubmitted state — the pending approval card, and any link
   * inside a streaming transcript.
   */
  newTab?: boolean;
  /**
   * A word before the name: "Check", "Open". Omitted by default so a link
   * inside a sentence reads as the record's name and nothing else.
   */
  verb?: string;
  className?: string;
}

export function RecordLink({ type, id, label, newTab = false, verb, className }: RecordLinkProps) {
  const href = recordHref(type, id);
  const name = label?.trim() || 'the record';

  /*
   * `min-h-11` even though this is a text link: it sits in the approval card's
   * footer beside two 44px buttons and inside transcript prose, and both are
   * places a thumb lands. The 44px floor is the primitive set's oldest rule and
   * an inline link is not an exemption from it.
   *
   * `text-xs` is the approval footer's size and the default here; a caller
   * inside 14px prose passes `className="text-sm"` and `cn()` resolves it,
   * rather than this growing a size prop for two values.
   */
  const shared =
    'inline-flex min-h-11 w-fit max-w-full items-center gap-1 rounded-lg text-xs ' +
    'text-muted underline-offset-4 transition-colors duration-1 ease-enter ' +
    'hover:text-fg hover:underline focus-visible:text-fg focus-visible:outline-none ' +
    'focus-visible:ring-2 focus-visible:ring-brand focus-visible:ring-offset-2 ' +
    'focus-visible:ring-offset-bg';

  if (!href) {
    return (
      <span className={cn('inline-flex max-w-full items-center text-xs text-muted', className)}>
        <span className="truncate">{name}</span>
      </span>
    );
  }

  const destination = opensRecord(type)
    ? `Open ${name}`
    : `Open the list containing ${name}`;

  return (
    <Link
      to={href}
      className={cn(shared, className)}
      title={newTab ? `${destination} in a new tab` : destination}
      {...(newTab ? { target: '_blank', rel: 'noopener noreferrer' } : {})}
    >
      <span className="truncate">
        {verb ? `${verb} ` : ''}
        {name}
      </span>
      <ArrowUpRight className="size-3.5 shrink-0" aria-hidden />
      {/* The title attribute is not announced reliably, and where this link
          lands is the one thing a screen-reader user must be told before they
          follow it out of a pending approval: that it opens a new tab, and —
          for every kind but `account`, which is the only per-record route PIG
          has — that it opens the list rather than the row. The honest wording
          existed already but lived only in `title`, which is neither visible
          nor announced. */}
      {opensRecord(type) && !newTab ? null : (
        <span className="sr-only">
          {opensRecord(type) ? '' : ' (opens the list containing it)'}
          {newTab ? ' (opens in a new tab)' : ''}
        </span>
      )}
    </Link>
  );
}
