/**
 * XSS 방지 및 입력값 살균 유틸리티
 *
 * 보안 목적:
 * - 사용자 입력에서 위험한 HTML/JS 코드 제거
 * - API 응답 데이터의 안전한 렌더링
 * - localStorage 데이터의 안전한 파싱
 */

/**
 * HTML 특수문자 이스케이프
 * XSS 공격에 사용되는 문자를 안전한 HTML 엔티티로 변환
 */
export function escapeHtml(str: string): string {
  const htmlEscapeMap: Record<string, string> = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#x27;',
    '/': '&#x2F;',
  };
  return str.replace(/[&<>"'/]/g, (char) => htmlEscapeMap[char] || char);
}

/**
 * HTML 태그 제거 (텍스트만 추출)
 * dangerouslySetInnerHTML 대신 사용
 */
export function stripHtmlTags(html: string): string {
  return html.replace(/<[^>]*>/g, '');
}

/**
 * 안전한 HTML 살균
 * 허용된 태그만 남기고 위험한 태그/속성 제거
 */
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const ALLOWED_TAGS = new Set([
  'b',
  'i',
  'u',
  'strong',
  'em',
  'br',
  'p',
  'span',
  'div',
  'h1',
  'h2',
  'h3',
  'h4',
  'h5',
  'h6',
  'ul',
  'ol',
  'li',
  'a',
  'img',
  'table',
  'thead',
  'tbody',
  'tr',
  'th',
  'td',
  'sup',
  'sub',
  'hr',
  'blockquote',
  'pre',
  'code',
]);

const DANGEROUS_ATTRS = /\s*on\w+\s*=|javascript\s*:|vbscript\s*:|expression\s*\(/gi;

export function sanitizeHtml(html: string): string {
  // 1. script 태그 완전 제거
  let sanitized = html.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');

  // 2. 위험한 이벤트 핸들러 속성 제거 (onclick, onerror 등)
  sanitized = sanitized.replace(DANGEROUS_ATTRS, '');

  // 3. data: URI 스킴 제거 (base64 인코딩된 스크립트 방지)
  sanitized = sanitized.replace(/\bdata\s*:\s*text\/html/gi, '');

  // 4. style 속성에서 expression() 제거 (IE CSS XSS)
  sanitized = sanitized.replace(/style\s*=\s*["'][^"']*expression\s*\([^)]*\)[^"']*["']/gi, '');

  // 5. iframe, object, embed 태그 제거
  sanitized = sanitized.replace(
    /<\s*(iframe|object|embed|form|input|textarea|button)\b[^>]*>/gi,
    '',
  );
  sanitized = sanitized.replace(/<\/\s*(iframe|object|embed|form|input|textarea|button)\s*>/gi, '');

  return sanitized;
}

/**
 * 사용자 입력 텍스트 살균
 * 게시판, 검색 등에서 사용
 */
export function sanitizeInput(input: string, maxLength = 1000): string {
  if (typeof input !== 'string') return '';
  return input
    .trim()
    .slice(0, maxLength)
    .replace(/[<>"'`;]/g, ''); // 위험 특수문자 제거
}

/**
 * URL 파라미터 안전하게 인코딩
 */
export function sanitizeUrlParam(param: string): string {
  return encodeURIComponent(param);
}

/**
 * 안전한 JSON 파싱 (localStorage 등에서 사용)
 * 파싱 실패 시 기본값 반환
 */
export function safeJsonParse<T>(json: string, defaultValue: T): T {
  try {
    const parsed = JSON.parse(json);
    if (parsed === null || parsed === undefined) return defaultValue;
    return parsed as T;
  } catch {
    return defaultValue;
  }
}

/**
 * 안전한 localStorage 읽기
 */
export function safeGetLocalStorage<T>(key: string, defaultValue: T): T {
  try {
    const raw = localStorage.getItem(key);
    if (raw === null) return defaultValue;
    return safeJsonParse(raw, defaultValue);
  } catch {
    return defaultValue;
  }
}

/**
 * 안전한 localStorage 저장 (크기 제한 포함)
 */
export function safeSetLocalStorage(key: string, value: unknown, maxSizeKB = 5120): boolean {
  try {
    const json = JSON.stringify(value);
    // 크기 제한 검사 (기본 5MB)
    if (json.length > maxSizeKB * 1024) {
      console.warn(`localStorage 저장 크기 초과: ${key}`);
      return false;
    }
    localStorage.setItem(key, json);
    return true;
  } catch {
    return false;
  }
}

/**
 * 안전한 PDF 내보내기 (document.write 대체)
 * Blob URL을 사용하여 새 창에서 콘텐츠 표시
 */
export function safePrintHtml(htmlContent: string, title: string, styles: string = ''): void {
  // HTML 콘텐츠에서 위험 요소 살균
  const sanitizedContent = sanitizeHtml(htmlContent);

  const fullHtml = `<!DOCTYPE html>
<html><head>
<meta charset="utf-8"/>
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:;">
<title>${escapeHtml(title)}</title>
${styles}
</head><body>${sanitizedContent}</body></html>`;

  // Blob URL 사용 (document.write 대체)
  const blob = new Blob([fullHtml], { type: 'text/html; charset=utf-8' });
  const url = URL.createObjectURL(blob);
  const win = window.open(url, '_blank');

  // Blob URL 정리 (메모리 누수 방지)
  if (win) {
    win.addEventListener('afterprint', () => URL.revokeObjectURL(url));
    // 30초 후 자동 정리
    setTimeout(() => URL.revokeObjectURL(url), 30000);
  } else {
    URL.revokeObjectURL(url);
  }
}

/**
 * 문자열에서 줄바꿈을 <br>로 변환 (안전하게)
 * dangerouslySetInnerHTML 없이 React 엘리먼트로 반환
 */
export function splitByNewline(text: string): string[] {
  return escapeHtml(text).split(/\n/);
}
