import { Typography } from 'antd';
import { normalizeChatResourceUrl } from '../../app/main/mainChatPanel/chatResourceUrl';
import { InlineImage } from '../common/InlineImage';
import { CodexDiffBlock } from '../previewer';
import { inferCodeLanguage, renderEditorBlock } from '../previewer/renderers';

const { Paragraph, Text, Title } = Typography;
const docsAssetUrls = import.meta.glob('/docs/assets/**/*.{png,jpg,jpeg,gif,webp,svg}', {
  eager: true,
  import: 'default',
}) as Record<string, string>;

type MarkdownPreviewContentProps = {
  content: string;
  documentPath?: string;
  maxBlocks?: number;
};

function resolveRelativePath(basePath: string, targetPath: string) {
  const baseSegments = basePath.split('/').filter(Boolean);
  baseSegments.pop();

  for (const segment of targetPath.split('/').filter(Boolean)) {
    if (segment === '.') {
      continue;
    }

    if (segment === '..') {
      baseSegments.pop();
      continue;
    }

    baseSegments.push(segment);
  }

  return `/${baseSegments.join('/')}`;
}

function resolveImageSource(documentPath: string | undefined, imagePath: string) {
  if (/^(https?:)?\/\//.test(imagePath) || imagePath.startsWith('data:')) {
    return normalizeChatResourceUrl(imagePath);
  }

  const normalizedPath = imagePath.startsWith('/')
    ? imagePath
    : resolveRelativePath(documentPath ?? '/', imagePath);

  return normalizeChatResourceUrl(docsAssetUrls[normalizedPath] ?? normalizedPath);
}

function resolveLinkHref(documentPath: string | undefined, href: string) {
  if (/^(https?:)?\/\//.test(href) || href.startsWith('mailto:') || href.startsWith('#')) {
    return href.startsWith('#') ? href : normalizeChatResourceUrl(href);
  }

  const normalizedPath = href.startsWith('/')
    ? href
    : resolveRelativePath(documentPath ?? '/', href);

  return normalizeChatResourceUrl(docsAssetUrls[normalizedPath] ?? normalizedPath);
}

function renderInline(text: string, documentPath?: string) {
  const parts = text.split(/(`[^`]+`|\[[^\]]+\]\([^)]+\))/g);

  return parts.map((part, index) => {
    if (part.startsWith('`') && part.endsWith('`')) {
      return (
        <Text code key={`${part}-${index}`}>
          {part.slice(1, -1)}
        </Text>
      );
    }

    const markdownLinkMatch = part.match(/^\[([^\]]+)\]\(([^)]+)\)$/);

    if (markdownLinkMatch) {
      const [, label, href] = markdownLinkMatch;
      return (
        <a
          key={`${part}-${index}`}
          href={resolveLinkHref(documentPath, href.trim())}
          target="_blank"
          rel="noreferrer"
        >
          {label.trim()}
        </a>
      );
    }

    return part;
  });
}

export function MarkdownPreviewContent({
  content,
  documentPath,
  maxBlocks,
}: MarkdownPreviewContentProps) {
  const lines = content.split('\n');
  const blocks: React.ReactNode[] = [];
  let index = 0;
  const hasBlockLimit = Number.isFinite(maxBlocks);

  while (index < lines.length && (!hasBlockLimit || blocks.length < (maxBlocks ?? 0))) {
    const line = lines[index].trimEnd();

    if (!line.trim()) {
      index += 1;
      continue;
    }

    if (line.startsWith('### ')) {
      blocks.push(
        <Title level={5} key={`h3-${index}`}>
          {line.slice(4)}
        </Title>,
      );
      index += 1;
      continue;
    }

    if (line.startsWith('## ')) {
      blocks.push(
        <Title level={4} key={`h2-${index}`}>
          {line.slice(3)}
        </Title>,
      );
      index += 1;
      continue;
    }

    if (line.startsWith('# ')) {
      blocks.push(
        <Title level={3} key={`h1-${index}`}>
          {line.slice(2)}
        </Title>,
      );
      index += 1;
      continue;
    }

    if (line.startsWith('- ')) {
      const items: string[] = [];

      while (index < lines.length && lines[index].trim().startsWith('- ')) {
        items.push(lines[index].trim().slice(2));
        index += 1;
      }

      blocks.push(
        <ul className="markdown-preview__list" key={`ul-${index}`}>
          {items.map((item, itemIndex) => (
            <li key={`${item}-${itemIndex}`}>{renderInline(item, documentPath)}</li>
          ))}
        </ul>,
      );
      continue;
    }

    if (line.startsWith('```')) {
      const codeLanguage = inferCodeLanguage(line.slice(3).trim() || 'text');
      const codeLines: string[] = [];
      index += 1;

      while (index < lines.length && !lines[index].trim().startsWith('```')) {
        codeLines.push(lines[index]);
        index += 1;
      }

      index += 1;
      blocks.push(
        codeLanguage === 'diff' ? (
          <div className="markdown-preview__code" key={`code-${index}`}>
            <CodexDiffBlock diffText={codeLines.join('\n')} />
          </div>
        ) : (
          <div className="markdown-preview__code" key={`code-${index}`}>
            {renderEditorBlock(codeLines.join('\n'), codeLanguage, 'code')}
          </div>
        ),
      );
      continue;
    }

    const imageMatch = line.match(/^!\[(.*)\]\((.+)\)$/);

    if (imageMatch) {
      const [, alt, src] = imageMatch;
      blocks.push(
        <InlineImage
          key={`img-${index}`}
          className="markdown-preview__image"
          src={resolveImageSource(documentPath, src.trim())}
          alt={alt.trim() || 'markdown image'}
          fallbackText="문서 이미지를 불러오지 못했습니다."
        />,
      );
      index += 1;
      continue;
    }

    const paragraphLines: string[] = [line];
    index += 1;

    while (index < lines.length && lines[index].trim() && !/^#{1,3}\s/.test(lines[index].trim())) {
      if (lines[index].trim().startsWith('- ') || lines[index].trim().startsWith('```')) {
        break;
      }
      paragraphLines.push(lines[index].trim());
      index += 1;
    }

    blocks.push(
      <Paragraph key={`p-${index}`}>{renderInline(paragraphLines.join(' '), documentPath)}</Paragraph>,
    );
  }

  return <div className="markdown-preview">{blocks}</div>;
}
