import React, { useRef, useState } from 'react';

import {
  extractHeadings,
  markdownToHtml,
  markdownToPlainText,
  type TocEntry,
} from '../visibility/MarkdownView';
import { copyToClipboard } from '../../lib/clipboard';
import {
  diffToCleanHtml,
  dropEmptyDiffTags,
  faqPairsToHtml,
  htmlToPlainText,
  injectHeadingIds,
  looksLikeHtml,
  parseFaqPairs,
  splitTitleFromBody,
} from '../../lib/inline-result-html';
import type { InlineGenerateMode } from '../../service/content-generator/content-generator.interface';

/**
 * Rendered-content styling. ``<ins>`` = additions (green), ``<del>`` =
 * removals (red, struck through), ``<mark>`` = highlight (green). Scoped with
 * Tailwind arbitrary-variant selectors so it never leans on a typography
 * plugin.
 */
const RENDERED_CLASS =
  'space-y-2 text-sm leading-relaxed text-gray-900 [&_h1]:text-lg [&_h1]:font-semibold [&_h2]:mt-3 [&_h2]:font-semibold [&_h3]:mt-3 [&_h3]:font-semibold [&_h4]:font-semibold [&_p]:my-1 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:list-decimal [&_ol]:pl-5 [&_li]:my-0.5 [&_strong]:font-semibold [&_mark]:rounded [&_mark]:bg-emerald-100 [&_mark]:px-0.5 [&_mark]:text-emerald-800 [&_ins]:rounded [&_ins]:bg-emerald-100 [&_ins]:px-0.5 [&_ins]:text-emerald-800 [&_ins]:no-underline [&_del]:rounded [&_del]:bg-red-100 [&_del]:px-0.5 [&_del]:text-red-700 [&_del]:line-through';

type CopyKind = 'title' | 'html' | 'text';

/** Props for {@link InlineResultCard}. */
interface InlineResultCardProps {
  mode: InlineGenerateMode;
  content: string;
}

/**
 * Renders a generated result the way it will look on the product page: HTML
 * (with ``<ins>``/``<del>`` diff for gap) rendered, FAQ as Q&A. Title
 * (gap/rewrite) splits into its own block with its own Copy title. An HTML
 * toggle, a Sections sidebar (when the body has headings), and Copy HTML /
 * Copy text (diff marks stripped to the final clean version) round it out.
 *
 * @param {InlineResultCardProps} props - Mode and generated content.
 * @return {JSX.Element} The result card.
 */
const InlineResultCard = ({
  mode,
  content,
}: InlineResultCardProps): JSX.Element => {
  const [showCode, setShowCode] = useState<boolean>(false);
  const [copied, setCopied] = useState<CopyKind | null>(null);
  const bodyRef = useRef<HTMLDivElement>(null);

  const titled = mode === 'rewrite' || mode === 'gap';
  const split = titled
    ? splitTitleFromBody(content)
    : { title: '', body: content };
  const titleText = split.title;
  const body = split.body;

  const isHtml = looksLikeHtml(body);
  const faqPairs = !isHtml ? parseFaqPairs(body) : [];
  const isFaq = faqPairs.length > 0;
  const cleanBody = isHtml ? dropEmptyDiffTags(body) : body;

  let renderedBody: JSX.Element;
  let toc: TocEntry[] = [];
  if (isFaq) {
    renderedBody = (
      <dl className="space-y-3">
        {faqPairs.map((pair, pairIndex) => (
          <div key={pairIndex} className="space-y-0.5">
            <dt className="text-sm font-semibold text-gray-900">{pair.q}</dt>
            <dd className="text-sm leading-relaxed text-gray-600">{pair.a}</dd>
          </div>
        ))}
      </dl>
    );
  } else {
    const processed = isHtml
      ? injectHeadingIds(cleanBody)
      : { html: markdownToHtml(cleanBody), toc: extractHeadings(cleanBody) };
    toc = processed.toc;
    renderedBody = (
      <div
        className={RENDERED_CLASS}
        dangerouslySetInnerHTML={{ __html: processed.html }}
      />
    );
  }

  const htmlVersion = isHtml
    ? diffToCleanHtml(cleanBody)
    : isFaq
      ? faqPairsToHtml(faqPairs)
      : markdownToHtml(cleanBody);
  const textVersion = isHtml
    ? htmlToPlainText(diffToCleanHtml(cleanBody))
    : isFaq
      ? body
      : markdownToPlainText(cleanBody);

  const flash = (kind: CopyKind): void => {
    setCopied(kind);
    window.setTimeout(() => setCopied(null), 2000);
  };
  const copy = async (kind: 'html' | 'text'): Promise<void> => {
    if (await copyToClipboard(kind === 'html' ? htmlVersion : textVersion)) {
      flash(kind);
    }
  };
  const copyTitle = async (): Promise<void> => {
    if (titleText && (await copyToClipboard(titleText))) flash('title');
  };

  const scrollToHeading = (slug: string): void => {
    bodyRef.current
      ?.querySelector(`[id="${CSS.escape(slug)}"]`)
      ?.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  const copyButtonClass =
    'inline-flex items-center gap-1.5 rounded-md border border-gray-200 bg-white px-2 py-1 text-xs font-medium text-gray-700 hover:bg-gray-50';

  return (
    <div className="space-y-3">
      <div className="flex flex-wrap items-center justify-end gap-1.5">
        {!isFaq && (
          <button
            type="button"
            onClick={() => setShowCode(current => !current)}
            className={copyButtonClass}
          >
            {showCode ? 'Rendered' : 'HTML'}
          </button>
        )}
        <button
          type="button"
          onClick={() => copy('html')}
          className={copyButtonClass}
        >
          {copied === 'html' ? 'Copied' : 'Copy HTML'}
        </button>
        <button
          type="button"
          onClick={() => copy('text')}
          className={copyButtonClass}
        >
          {copied === 'text' ? 'Copied' : 'Copy text'}
        </button>
      </div>

      {titled && titleText && (
        <div className="flex items-center justify-between gap-2 rounded-md border border-gray-200 bg-gray-50 p-3">
          <div className="min-w-0">
            <p className="text-[11px] font-semibold uppercase tracking-wider text-gray-500">
              Title
            </p>
            <p className="text-sm font-medium text-gray-900">{titleText}</p>
          </div>
          <button
            type="button"
            onClick={copyTitle}
            className={`shrink-0 ${copyButtonClass}`}
          >
            {copied === 'title' ? 'Copied' : 'Copy title'}
          </button>
        </div>
      )}

      <div
        className={
          toc.length > 0 && !showCode
            ? 'grid min-w-0 gap-4 lg:grid-cols-[200px_minmax(0,1fr)]'
            : 'min-w-0'
        }
      >
        {toc.length > 0 && !showCode && (
          <nav className="hidden max-h-[55vh] overflow-y-auto border-r border-gray-200 pr-3 lg:block">
            <p className="mb-2 text-[11px] font-semibold uppercase tracking-wider text-gray-500">
              Sections
            </p>
            <ul className="space-y-1">
              {toc.map(entry => (
                <li key={entry.slug}>
                  <button
                    type="button"
                    onClick={() => scrollToHeading(entry.slug)}
                    style={{ paddingLeft: `${(entry.level - 1) * 10}px` }}
                    className="block w-full truncate text-left text-xs text-gray-500 hover:text-gray-900"
                  >
                    {entry.text}
                  </button>
                </li>
              ))}
            </ul>
          </nav>
        )}
        <div
          ref={bodyRef}
          className="min-w-0 max-h-[55vh] overflow-y-auto break-words rounded-md border border-gray-200 bg-white p-4"
        >
          {showCode ? (
            <pre className="whitespace-pre-wrap break-words text-xs leading-relaxed text-gray-600">
              {htmlVersion}
            </pre>
          ) : (
            renderedBody
          )}
        </div>
      </div>
    </div>
  );
};

export default InlineResultCard;
