/**
 * 마크다운 + KaTeX 수식 통합 렌더링 (PR-7).
 *
 * 적용:
 *   - $...$ inline math
 *   - $$...$$ block math
 *   - 일반 markdown (**굵게**, 리스트, 코드 등) — DocumentViewer 와 동일 출력 호환
 *
 * 사용:
 *   import { renderMathMarkdown } from '$lib/utils/mathMarkdown';
 *   <div class="prose prose-sm prose-invert max-w-none">{@html renderMathMarkdown(text)}</div>
 *
 * 주의:
 *   - 입력값은 그대로 저장. 변환은 표시 시점에만.
 *   - 수식 렌더 실패 시 fallback (KaTeX throwOnError: false → 잘못된 수식은 빨간 텍스트로 표시).
 *   - DOMPurify 로 XSS 차단. KaTeX HTML span/class/style 만 허용.
 *   - 통합뷰 카드 같은 곳에서는 raw 텍스트 보존이 더 자연스러움 → 호출 안 함.
 */

import DOMPurify from 'dompurify';
import { Marked } from 'marked';
// @ts-ignore — marked-katex-extension 타입 정의 누락 시 무시
import markedKatex from 'marked-katex-extension';
import 'katex/dist/katex.min.css';

// 별도 인스턴스 — 글로벌 marked 사용처(DocumentViewer 등) 영향 없음.
const mathMarked = new Marked();
mathMarked.use({ mangle: false, headerIds: false } as any);
mathMarked.use(
  markedKatex({
    // 잘못된 수식이면 빨간색으로 그대로 출력 (페이지 깨지지 않음)
    throwOnError: false,
    // 단일 $ inline / 이중 $$ block 모두 지원
    nonStandard: false,
    // KaTeX HTML 출력만 (MathML 비활성). DOMPurify HTML profile 만으로 충분.
    output: 'html',
  } as any),
);

const SANITIZE_OPTS = {
  USE_PROFILES: { html: true },
  // KaTeX 가 inline style + aria-hidden 사용. class 는 USE_PROFILES.html 기본 허용.
  ADD_ATTR: ['style', 'aria-hidden'],
  FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'link', 'meta'],
  FORBID_ATTR: ['onerror', 'onclick', 'onload', 'onmouseover', 'onfocus'],
  ALLOW_UNKNOWN_PROTOCOLS: false,
} as const;

/**
 * 텍스트 전체가 단일 fenced code block 으로 감싸진 경우만 unwrap.
 *
 * 두 케이스 처리:
 *   (1) terminated: 시작 + 끝 모두 ``` — 백틱 그룹 정확히 2번
 *   (2) unterminated: 시작 ``` 만 있고 닫음 누락 — 백틱 그룹 정확히 1번
 *
 * 보존 케이스 (그대로):
 *   설명 문장
 *   ```python
 *   print("hi")
 *   ```
 *   추가 설명
 *   → 백틱 그룹이 2 이상이지만 ``` 가 본문 중간에 있어 wrap 패턴 매칭 안 됨.
 *
 * 안전 조건:
 *   - terminated: inner 에 ``` 가 또 있으면 보존 (사용자가 진짜 코드블록 의도).
 *   - unterminated: 본문에 ``` 가 그 시작 한 번만 있어야 함 (백틱 그룹 = 1).
 *
 * AI 응답이 마크다운 자체를 ``` 으로 감싸서 오는 패턴을 자동 처리.
 */
function stripOuterFence(text: string): string {
  const trimmed = text.trim();

  // (1) terminated wrap: ```...\n본문\n``` 끝.
  const term = trimmed.match(/^```[A-Za-z0-9_-]*[ \t]*\n([\s\S]*?)\n```$/);
  if (term) {
    const inner = term[1];
    if (!inner.includes('```')) return inner;
    return text;
  }

  // (2) unterminated: 시작 ``` 만, 본문 중에 ``` 가 더 없음.
  const backtickGroups = (trimmed.match(/```/g) || []).length;
  if (backtickGroups === 1) {
    const unterm = trimmed.match(/^```[A-Za-z0-9_-]*[ \t]*\n([\s\S]*)$/);
    if (unterm) return unterm[1];
  }

  return text;
}

export function renderMathMarkdown(text: string | null | undefined): string {
  if (!text) return '';
  try {
    const normalized = stripOuterFence(text);
    const html = mathMarked.parse(normalized) as string;
    return DOMPurify.sanitize(html, SANITIZE_OPTS);
  } catch {
    return DOMPurify.sanitize(text, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
  }
}

/**
 * Inline 전용 렌더 — <p> 같은 block 태그로 감싸지 않는다.
 * 보기 1~4 처럼 줄 한 줄짜리 짧은 텍스트에 사용 (button 안에 <p>가 들어가면 레이아웃 깨짐).
 */
export function renderMathMarkdownInline(text: string | null | undefined): string {
  if (!text) return '';
  try {
    const html = mathMarked.parseInline(text) as string;
    return DOMPurify.sanitize(html, SANITIZE_OPTS);
  } catch {
    return DOMPurify.sanitize(text, { ALLOWED_TAGS: [], ALLOWED_ATTR: [] });
  }
}
