import sanitizeHtml from 'sanitize-html';

//* 기업별 약관 본문(agtContent) 저장형 XSS 차단용 화이트리스트 옵션
const TERMS_CONTENT_SANITIZE_OPTIONS: sanitizeHtml.IOptions = {
  allowedTags: [
    'p',
    'br',
    'span',
    'div',
    'b',
    'strong',
    'i',
    'em',
    'u',
    's',
    'ul',
    'ol',
    'li',
    'a',
    'h1',
    'h2',
    'h3',
    'h4',
    'h5',
    'h6',
    'table',
    'caption',
    'colgroup',
    'col',
    'thead',
    'tbody',
    'tfoot',
    'tr',
    'th',
    'td',
    'small',
    'pre',
    'blockquote',
    'hr',
  ],
  allowedAttributes: {
    'a': ['href', 'target', 'rel'],
    '*': ['class', 'width', 'colspan', 'rowspan', 'align', 'role'],
  },
  //* javascript: 등 위험 스킴 차단, 허용 스킴만 통과
  allowedSchemes: ['http', 'https', 'mailto'],
  //* 화이트리스트에 없는 태그(script·style·iframe 등)는 통째로 제거
  disallowedTagsMode: 'discard',
};

//* HTML 약관 본문을 화이트리스트 기반으로 정제하여 저장형 XSS를 차단한다.
//* 입력이 null/undefined면 그대로 반환하여 호출부의 타입을 보존한다.
export function sanitizeTermsContent<T extends string | null | undefined>(
  content: T,
): T {
  if (content === undefined || content === null) {
    return content;
  }
  return sanitizeHtml(content, TERMS_CONTENT_SANITIZE_OPTIONS) as T;
}

const BOARD_COLOR = [/^#[0-9a-f]{3,8}$/i, /^rgba?\([\d\s.,%]+\)$/i];

//* 게시판 본문은 관리자 에디터(react-quill)가 업로드 이미지와 글자색·배경색 인라인 style 을 쓴다.
//* 약관 목록에 이 둘만 더한다. 정렬·크기·글꼴·들여쓰기는 ql-* class 라 이미 통과한다.
const BOARD_CONTENT_SANITIZE_OPTIONS: sanitizeHtml.IOptions = {
  ...TERMS_CONTENT_SANITIZE_OPTIONS,
  allowedTags: [
    ...(TERMS_CONTENT_SANITIZE_OPTIONS.allowedTags as string[]),
    'img',
  ],
  allowedAttributes: {
    ...TERMS_CONTENT_SANITIZE_OPTIONS.allowedAttributes,
    'img': ['src', 'alt'],
    '*': ['class', 'width', 'colspan', 'rowspan', 'align', 'role', 'style'],
  },
  allowedSchemesByTag: { img: ['http', 'https'] },
  allowedStyles: {
    '*': { 'color': BOARD_COLOR, 'background-color': BOARD_COLOR },
  },
};

export function sanitizeBoardContent<T extends string | null | undefined>(
  content: T,
): T {
  if (content === undefined || content === null) {
    return content;
  }
  return sanitizeHtml(content, BOARD_CONTENT_SANITIZE_OPTIONS) as T;
}

//* 제목은 텍스트로만 렌더된다. 태그는 지우고 & 만 되돌린다. < > 는 이스케이프된 채 둬서
//* 저장값에 태그 문자가 남지 않게 한다.
export function sanitizeBoardTitle<T extends string | null | undefined>(
  title: T,
): T {
  if (title === undefined || title === null) {
    return title;
  }
  return sanitizeHtml(title, {
    allowedTags: [],
    allowedAttributes: {},
  }).replace(/&amp;/g, '&') as T;
}
