#!/usr/bin/env python3
"""ODL 범용 변환 스크립트 — convert()의 모든 옵션을 argparse로 노출.

--output-dir 지정 시: 해당 디렉토리에 파일 저장 후 경로 출력.
미지정 시: 임시 디렉토리에 저장 후 내용을 stdout으로 출력.
"""

import argparse
import os
import shutil
import sys
import tempfile
from typing import Optional


def _setup_java() -> None:
    java_home = os.environ.get("JAVA_HOME", "/home/jay/.local/jvm/jdk-11.0.2")
    os.environ["JAVA_HOME"] = java_home
    bin_dir = os.path.join(java_home, "bin")
    path = os.environ.get("PATH", "")
    if bin_dir not in path.split(os.pathsep):
        os.environ["PATH"] = bin_dir + os.pathsep + path


def _ext_for_format(fmt: str) -> str:
    mapping = {
        "markdown": ".md",
        "markdown-with-html": ".html",
        "markdown-with-images": ".md",
        "text": ".txt",
        "json": ".json",
        "html": ".html",
        "pdf": ".pdf",
    }
    return mapping.get(fmt, f".{fmt}")


def _find_output_file(output_dir: str, stem: str, fmt: Optional[str]) -> Optional[str]:
    """출력 디렉토리에서 결과 파일을 탐색."""
    if fmt is not None:
        ext = _ext_for_format(fmt)
        candidate = os.path.join(output_dir, stem + ext)
        if os.path.exists(candidate):
            return candidate
        # stem이 다를 수 있으므로 확장자로 재탐색
        for name in os.listdir(output_dir):
            if name.endswith(ext):
                return os.path.join(output_dir, name)

    # 형식 미지정(기본 json) 또는 위에서 못 찾은 경우: 첫 번째 파일 반환
    files = [
        os.path.join(output_dir, f)
        for f in os.listdir(output_dir)
        if os.path.isfile(os.path.join(output_dir, f))
    ]
    return files[0] if files else None


def _is_binary(file_path: str) -> bool:
    """파일이 바이너리인지 간단히 판별."""
    try:
        with open(file_path, "rb") as fp:
            chunk = fp.read(8192)
        return b"\x00" in chunk
    except OSError:
        return False


def main() -> None:
    parser = argparse.ArgumentParser(
        description="ODL convert()의 모든 옵션을 지원하는 범용 PDF 변환 스크립트.",
    )

    # 필수 인자
    parser.add_argument("input_path", help="입력 PDF 파일 경로")

    # 출력 제어
    parser.add_argument(
        "--output-dir",
        dest="output_dir",
        default=None,
        help="출력 디렉토리. 지정 시 파일로 저장하고 경로를 출력합니다.",
    )

    # convert() 옵션 전체
    parser.add_argument(
        "--password",
        default=None,
        help="암호화된 PDF의 비밀번호",
    )
    parser.add_argument(
        "--format",
        default=None,
        help=(
            "출력 형식. 복수 지정 시 쉼표 구분 "
            "(json|text|html|pdf|markdown|markdown-with-html|markdown-with-images). "
            "기본: json"
        ),
    )
    parser.add_argument(
        "--sanitize",
        action="store_true",
        default=False,
        help="민감정보(이메일, 전화번호 등)를 익명화합니다.",
    )
    parser.add_argument(
        "--keep-line-breaks",
        dest="keep_line_breaks",
        action="store_true",
        default=False,
        help="원본 줄바꿈을 보존합니다.",
    )
    parser.add_argument(
        "--replace-invalid-chars",
        dest="replace_invalid_chars",
        default=None,
        help="인식 불가 문자 대체 문자 (기본: 공백)",
    )
    parser.add_argument(
        "--use-struct-tree",
        dest="use_struct_tree",
        action="store_true",
        default=False,
        help="PDF 구조 트리(태그 PDF)를 읽기 순서에 활용합니다.",
    )
    parser.add_argument(
        "--table-method",
        dest="table_method",
        choices=["default", "cluster"],
        default=None,
        help="테이블 감지 방법 (기본: default)",
    )
    parser.add_argument(
        "--reading-order",
        dest="reading_order",
        choices=["off", "xycut"],
        default=None,
        help="읽기 순서 알고리즘 (기본: xycut)",
    )
    parser.add_argument(
        "--pages",
        default=None,
        help='추출할 페이지 범위 (예: "1,3,5-7"). 기본: 전체',
    )
    parser.add_argument(
        "--include-header-footer",
        dest="include_header_footer",
        action="store_true",
        default=False,
        help="페이지 헤더/푸터를 출력에 포함합니다.",
    )
    parser.add_argument(
        "--hybrid",
        choices=["off", "docling-fast"],
        default=None,
        help="AI 하이브리드 백엔드",
    )
    parser.add_argument(
        "--hybrid-mode",
        dest="hybrid_mode",
        choices=["auto", "full"],
        default=None,
        help="하이브리드 트리아지 모드 (기본: auto)",
    )
    parser.add_argument(
        "--hybrid-url",
        dest="hybrid_url",
        default=None,
        help="하이브리드 서버 URL",
    )
    parser.add_argument(
        "--hybrid-timeout",
        dest="hybrid_timeout",
        default=None,
        help="하이브리드 서버 타임아웃 (ms, 기본: 30000)",
    )
    parser.add_argument(
        "--hybrid-fallback",
        dest="hybrid_fallback",
        action="store_true",
        default=False,
        help="hybrid 백엔드 오류 시 Java로 폴백합니다.",
    )
    parser.add_argument(
        "--image-output",
        dest="image_output",
        choices=["off", "embedded", "external"],
        default=None,
        help="이미지 출력 모드 (기본: external)",
    )
    parser.add_argument(
        "--image-format",
        dest="image_format",
        choices=["png", "jpeg"],
        default=None,
        help="추출 이미지 형식 (기본: png)",
    )
    parser.add_argument(
        "--image-dir",
        dest="image_dir",
        default=None,
        help="추출된 이미지 저장 디렉토리",
    )
    parser.add_argument(
        "--markdown-page-separator",
        dest="markdown_page_separator",
        default=None,
        help="Markdown 출력에서 페이지 구분자 (%%page-number%% 사용 가능)",
    )
    parser.add_argument(
        "--text-page-separator",
        dest="text_page_separator",
        default=None,
        help="text 출력에서 페이지 구분자 (%%page-number%% 사용 가능)",
    )
    parser.add_argument(
        "--html-page-separator",
        dest="html_page_separator",
        default=None,
        help="HTML 출력에서 페이지 구분자 (%%page-number%% 사용 가능)",
    )
    parser.add_argument(
        "--content-safety-off",
        dest="content_safety_off",
        default=None,
        help="콘텐츠 안전 필터 비활성화 (all|hidden-text|off-page|tiny|hidden-ocg)",
    )

    args = parser.parse_args()

    if not os.path.isfile(args.input_path):
        print(f"오류: 파일을 찾을 수 없습니다: {args.input_path}", file=sys.stderr)
        sys.exit(1)

    _setup_java()

    from opendataloader_pdf import convert  # noqa: PLC0415

    # 사용자가 --output-dir을 직접 지정한 경우
    user_specified_output = args.output_dir is not None

    tmpdir: Optional[str] = None
    effective_output_dir: str

    if user_specified_output:
        effective_output_dir = args.output_dir  # type: ignore[assignment]
        os.makedirs(effective_output_dir, exist_ok=True)
    else:
        tmpdir = tempfile.mkdtemp()
        effective_output_dir = tmpdir

    try:
        convert(
            args.input_path,
            output_dir=effective_output_dir,
            password=args.password,
            format=args.format,
            quiet=True,
            content_safety_off=args.content_safety_off,
            sanitize=args.sanitize,
            keep_line_breaks=args.keep_line_breaks,
            replace_invalid_chars=args.replace_invalid_chars,
            use_struct_tree=args.use_struct_tree,
            table_method=args.table_method,
            reading_order=args.reading_order,
            markdown_page_separator=args.markdown_page_separator,
            text_page_separator=args.text_page_separator,
            html_page_separator=args.html_page_separator,
            image_output=args.image_output,
            image_format=args.image_format,
            image_dir=args.image_dir,
            pages=args.pages,
            include_header_footer=args.include_header_footer,
            hybrid=args.hybrid,
            hybrid_mode=args.hybrid_mode,
            hybrid_url=args.hybrid_url,
            hybrid_timeout=args.hybrid_timeout,
            hybrid_fallback=args.hybrid_fallback,
        )

        stem = os.path.splitext(os.path.basename(args.input_path))[0]

        # format에 쉼표가 있을 경우 첫 번째 형식으로 대표 파일 탐색
        primary_fmt: Optional[str] = None
        if args.format:
            primary_fmt = args.format.split(",")[0].strip()

        result_path = _find_output_file(effective_output_dir, stem, primary_fmt)
        if result_path is None:
            print(
                f"오류: 변환 결과 파일을 찾을 수 없습니다. (디렉토리: {effective_output_dir})",
                file=sys.stderr,
            )
            sys.exit(1)

        if user_specified_output:
            # 파일로 저장됨 — 경로를 출력
            print(result_path)
        else:
            # 결과 내용을 stdout으로 출력
            if _is_binary(result_path):
                sys.stdout.buffer.write(open(result_path, "rb").read())
            else:
                with open(result_path, encoding="utf-8") as fp:
                    sys.stdout.write(fp.read())

    except Exception as exc:
        print(f"오류: 변환 중 예외가 발생했습니다: {exc}", file=sys.stderr)
        sys.exit(1)
    finally:
        if tmpdir is not None:
            shutil.rmtree(tmpdir, ignore_errors=True)


if __name__ == "__main__":
    main()
