import React from 'react';
import { LuArrowRight, LuSparkles } from 'react-icons/lu';

/** Matches **bold**, `code`, and [label](href) inline tokens. */
const INLINE_TOKEN = /(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\([^)]+\))/g;

/**
 * The model sometimes prefixes a link/button label with the directive key
 * itself ("primary_action: View articles"); strip it so the chip reads cleanly.
 */
const ACTION_LABEL_PREFIX =
  /^\s*(?:primary|secondary)?[ _-]?action(?:[ _-]?(?:label|route|type))?\s*:\s*/i;

/**
 * Callback invoked when the merchant taps an internal-link chip. The panel
 * decides whether the href is a real plugin route (navigate) or an action the
 * copilot should act on (send the label as a follow-up message).
 *
 * @param href - The internal href the model wrote (always starts with ``/``).
 * @param label - The chip's cleaned label text.
 * @return Nothing.
 */
type OnLinkHandler = (href: string, label: string) => void;

/**
 * Renders a single inline token (bold, code, or link) or plain text.
 *
 * @param token - The raw token text.
 * @param index - Stable key index within the line.
 * @param onLink - Handler for internal-link chip taps.
 * @return The rendered node.
 */
function renderToken(
  token: string,
  index: number,
  onLink: OnLinkHandler
): React.ReactNode {
  if (token.startsWith('**') && token.endsWith('**')) {
    return (
      <strong key={index} className="font-semibold text-gray-900">
        {token.slice(2, -2)}
      </strong>
    );
  }

  if (token.startsWith('`') && token.endsWith('`')) {
    return (
      <code
        key={index}
        className="rounded bg-[#b7007c]/5 px-1 py-0.5 font-mono text-[0.85em] text-[#b7007c]"
      >
        {token.slice(1, -1)}
      </code>
    );
  }

  const linkMatch: RegExpMatchArray | null = token.match(
    /^\[([^\]]+)\]\(([^)]+)\)$/
  );
  if (linkMatch) {
    const label: string = linkMatch[1].replace(ACTION_LABEL_PREFIX, '');
    const href: string = linkMatch[2];
    const isInternal: boolean = href.startsWith('/');

    if (isInternal) {
      // Internal references render as a tappable chip. The model often writes
      // these as fake routes (e.g. "/confirm-schedule") for actions it should
      // perform rather than pages it can reach, so we don't navigate blindly -
      // ``onLink`` routes real plugin routes and sends everything else back to
      // the copilot as a follow-up message.
      return (
        <button
          key={index}
          type="button"
          onClick={() => onLink(href, label)}
          className="mx-0.5 inline-flex items-center gap-1.5 rounded-lg border border-[#b7007c]/20 bg-[#b7007c]/5 px-2 py-0.5 align-middle text-[13px] font-medium text-[#b7007c] transition hover:border-[#b7007c]/40 hover:bg-[#b7007c]/10"
        >
          <LuSparkles className="h-3 w-3 shrink-0" />
          {label}
          <LuArrowRight className="h-3 w-3 shrink-0 opacity-70" />
        </button>
      );
    }

    return (
      <a
        key={index}
        href={href}
        target="_blank"
        rel="noreferrer"
        className="font-medium text-[#b7007c] underline-offset-2 hover:underline"
      >
        {label}
      </a>
    );
  }

  return <span key={index}>{token}</span>;
}

/**
 * Splits a line into inline tokens and renders each.
 *
 * @param line - One line of markdown text.
 * @param onLink - Handler for internal-link chip taps.
 * @return Rendered inline nodes.
 */
function renderLine(line: string, onLink: OnLinkHandler): React.ReactNode[] {
  return line
    .split(INLINE_TOKEN)
    .filter((segment: string) => segment.length > 0)
    .map((segment: string, segmentIndex: number) =>
      renderToken(segment, segmentIndex, onLink)
    );
}

/**
 * Lightweight markdown renderer for copilot messages: paragraphs, simple
 * bullet/numbered lines, bold, inline code, and internal/external links.
 *
 * @param props - Component props.
 * @param props.content - The markdown content to render.
 * @param props.onLink - Handler invoked when an internal-link chip is tapped.
 * @return The rendered message body.
 */
export function CopilotMarkdown({
  content,
  onLink,
}: {
  content: string;
  onLink: OnLinkHandler;
}): React.ReactElement {
  const lines: string[] = content.split('\n');

  return (
    <div className="space-y-3 text-[13.5px] leading-relaxed text-gray-700">
      {lines.map((line: string, lineIndex: number) => {
        const trimmed: string = line.trim();
        if (!trimmed) return null;

        const isListItem: boolean = /^(-|\*|\d+\.)\s+/.test(trimmed);
        if (isListItem) {
          const text: string = trimmed.replace(/^(-|\*|\d+\.)\s+/, '');

          return (
            <div key={lineIndex} className="flex gap-2.5">
              <span className="mt-[7px] h-1 w-1 shrink-0 rounded-full bg-[#b7007c]" />
              <span className="flex-1">{renderLine(text, onLink)}</span>
            </div>
          );
        }

        return <p key={lineIndex}>{renderLine(line, onLink)}</p>;
      })}
    </div>
  );
}
