import React from 'react';

import { CopyButton } from '@renderer/components/common/CopyButton';
import { PROSE_BODY } from '@renderer/constants/cssVariables';

import { extractTextFromReactNode } from './markdownCopyUtils';
import { highlightSearchInChildren, type SearchContext } from './searchHighlightUtils';
import { FileLink, isRelativeUrl } from './viewers/FileLink';

import type { Components } from 'react-markdown';

interface MarkdownComponentOptions {
  copyCodeBlocks?: boolean;
}

/**
 * Create inline markdown components for rendering prose content.
 * When searchCtx is provided, search term highlighting is applied
 * to text nodes while preserving full markdown rendering.
 */
export function createMarkdownComponents(
  searchCtx: SearchContext | null,
  options: MarkdownComponentOptions = {}
): Components {
  const { copyCodeBlocks = false } = options;
  const hl = (children: React.ReactNode): React.ReactNode =>
    searchCtx ? highlightSearchInChildren(children, searchCtx) : children;

  return {
    // Headings - Bold text with generous spacing to break up content
    h1: ({ children }) => (
      <h1
        className="mb-3 mt-6 text-lg font-semibold first:mt-0"
        style={{ color: 'var(--prose-heading)' }}
      >
        {hl(children)}
      </h1>
    ),
    h2: ({ children }) => (
      <h2
        className="mb-2 mt-5 text-base font-semibold first:mt-0"
        style={{ color: 'var(--prose-heading)' }}
      >
        {hl(children)}
      </h2>
    ),
    h3: ({ children }) => (
      <h3
        className="mb-2 mt-4 text-sm font-semibold first:mt-0"
        style={{ color: 'var(--prose-heading)' }}
      >
        {hl(children)}
      </h3>
    ),
    h4: ({ children }) => (
      <h4
        className="mb-1.5 mt-3 text-sm font-semibold first:mt-0"
        style={{ color: 'var(--prose-heading)' }}
      >
        {hl(children)}
      </h4>
    ),
    h5: ({ children }) => (
      <h5
        className="mb-1 mt-2 text-sm font-medium first:mt-0"
        style={{ color: 'var(--prose-heading)' }}
      >
        {hl(children)}
      </h5>
    ),
    h6: ({ children }) => (
      <h6
        className="mb-1 mt-2 text-xs font-medium first:mt-0"
        style={{ color: 'var(--prose-heading)' }}
      >
        {hl(children)}
      </h6>
    ),

    // Paragraphs
    p: ({ children }) => (
      <p
        className="my-2 text-sm leading-relaxed first:mt-0 last:mb-0"
        style={{ color: PROSE_BODY }}
      >
        {hl(children)}
      </p>
    ),

    // Links — inline element, no hl(); parent block element's hl() descends here
    a: ({ href, children }) => {
      if (href && isRelativeUrl(href)) {
        return <FileLink href={href}>{children}</FileLink>;
      }
      return (
        <a
          href={href}
          className="no-underline hover:underline"
          style={{ color: 'var(--prose-link)' }}
          target="_blank"
          rel="noopener noreferrer"
        >
          {children}
        </a>
      );
    },

    // Strong/Bold — inline element, no hl()
    strong: ({ children }) => (
      <strong className="font-semibold" style={{ color: 'var(--prose-heading)' }}>
        {children}
      </strong>
    ),

    // Emphasis/Italic — inline element, no hl()
    em: ({ children }) => (
      <em className="italic" style={{ color: PROSE_BODY }}>
        {children}
      </em>
    ),

    // Strikethrough — inline element, no hl()
    del: ({ children }) => (
      <del className="line-through" style={{ color: PROSE_BODY }}>
        {children}
      </del>
    ),

    // Inline code vs block code (block is highlighted by rehype-highlight; preserve hljs class)
    code: ({ className, children }) => {
      const hasLanguageClass = className?.includes('language-');
      const content = typeof children === 'string' ? children : '';
      const isMultiLine = content.includes('\n');
      const isBlock = (hasLanguageClass ?? false) || isMultiLine;

      if (isBlock) {
        return (
          <code
            className={`block font-mono text-xs ${className ?? ''}`.trim()}
            style={{ color: 'var(--color-text)' }}
          >
            {hl(children)}
          </code>
        );
      }
      // Inline code — no hl(); parent block element's hl() descends here
      return (
        <code
          className="rounded px-1.5 py-0.5 font-mono text-xs"
          style={{
            backgroundColor: 'var(--prose-code-bg)',
            color: 'var(--prose-code-text)',
          }}
        >
          {children}
        </code>
      );
    },

    // Code blocks
    pre: ({ children }) => {
      const codeText = copyCodeBlocks ? extractTextFromReactNode(children).trim() : '';

      return (
        <pre
          className={`my-3 overflow-x-auto rounded-lg p-3 font-mono text-xs leading-relaxed ${codeText ? 'group relative' : ''}`.trim()}
          style={{
            backgroundColor: 'var(--prose-pre-bg)',
            border: '1px solid var(--prose-pre-border)',
            color: 'var(--color-text)',
          }}
        >
          {codeText ? <CopyButton text={codeText} /> : null}
          {children}
        </pre>
      );
    },

    // Blockquotes
    blockquote: ({ children }) => (
      <blockquote
        className="my-3 border-l-4 pl-4 italic"
        style={{
          borderColor: 'var(--prose-blockquote-border)',
          color: 'var(--prose-muted)',
        }}
      >
        {hl(children)}
      </blockquote>
    ),

    // Lists
    ul: ({ children }) => (
      <ul className="my-2 list-disc space-y-1 pl-5" style={{ color: PROSE_BODY }}>
        {children}
      </ul>
    ),
    ol: ({ children }) => (
      <ol className="my-2 list-decimal space-y-1 pl-5" style={{ color: PROSE_BODY }}>
        {children}
      </ol>
    ),
    li: ({ children }) => (
      <li className="text-sm" style={{ color: PROSE_BODY }}>
        {hl(children)}
      </li>
    ),

    // Tables
    table: ({ children }) => (
      <div className="my-3 overflow-x-auto">
        <table
          className="min-w-full border-collapse text-sm"
          style={{ borderColor: 'var(--prose-table-border)' }}
        >
          {children}
        </table>
      </div>
    ),
    thead: ({ children }) => (
      <thead style={{ backgroundColor: 'var(--prose-table-header-bg)' }}>{children}</thead>
    ),
    th: ({ children }) => (
      <th
        className="px-3 py-2 text-left font-semibold"
        style={{
          border: '1px solid var(--prose-table-border)',
          color: 'var(--prose-heading)',
        }}
      >
        {hl(children)}
      </th>
    ),
    td: ({ children }) => (
      <td
        className="px-3 py-2"
        style={{
          border: '1px solid var(--prose-table-border)',
          color: PROSE_BODY,
        }}
      >
        {hl(children)}
      </td>
    ),

    // Horizontal rule
    hr: () => <hr className="my-4" style={{ borderColor: 'var(--prose-table-border)' }} />,
  };
}

/** Default markdown components without search highlighting (used by CompactBoundary) */
export const markdownComponents: Components = createMarkdownComponents(null);

/** Markdown components for message-style content with both whole-message and code-block copy */
export const markdownComponentsWithCodeCopy: Components = createMarkdownComponents(null, {
  copyCodeBlocks: true,
});
