#!/usr/bin/env python3
"""
apply-bold-pdf.py — Áp dụng in đậm từ PDF sang Markdown

Luồng xử lý:
  1. Đọc PDF, trích xuất tất cả span chữ đậm (kiểm tra flags bit 4 hoặc font name có "Bold")
  2. Lọc: chỉ giữ fragment có ý nghĩa (>=4 ký tự, không nhiễu)
  3. Với mỗi dòng body text (không phải heading ##/###, separator, URL):
     - Tìm fragment đậm dài nhất khớp đầu dòng
     - Bọc trong **...**
  4. Loại trừ từ khóa gây dương tính giả: "Chánh Kiến", "Nghiệp", "nghiệp"

Cách dùng:
  python3 apply-bold-pdf.py [output.md]

Nếu không có output, ghi ra Chanh-Kien-Va-Nghiep-bold.md
"""

import re
import sys
import fitz
from pathlib import Path
from collections import Counter

# ── Đường dẫn ──────────────────────────────────────────────────────────────
PDF_PATH = "/home/tuan-nguyen/Downloads/Chanh Kien Va Nghiep.pdf"
MD_PATH  = "/home/tuan-nguyen/Documents/Doc/Chanh-Kien-Va-Nghiep-original.md"

# ── Nhiễu: bỏ qua ─────────────────────────────────────────────────────────
SKIP_SET = {
    '---o0o---', '---o0o--', '--', '---', '...',
    '–', '– ,',
}

# Fragment ngắn toàn chữ cái (Và, A, B, v.v.)
SHORT_ALPHA_MAX = 5
SKIP_PATTERN = re.compile(r'^[\d\s.,\-–—()*\[\]{}:;!?@#$%^&+=/\\\'"`~<>|]+$')

# Từ khóa gây dương tính giả (xuất hiện đậm trong Mục Lục PDF, không phải body text)
EXCLUDE_FRAGMENTS = {
    'Chánh Kiến',
    'Nghiệp',
    'nghiệp',
}

# ── Bước 1: Trích xuất chữ đậm từ PDF ────────────────────────────────────
def extract_bold_fragments(pdf_path: str) -> set:
    """Trích xuất tất cả bold fragment duy nhất từ PDF."""
    doc = fitz.open(pdf_path)
    raw = set()

    for pno in range(len(doc)):
        page = doc[pno]
        blocks = page.get_text('dict')['blocks']
        for b in blocks:
            if b['type'] != 0:
                continue
            for line in b['lines']:
                combined = ''
                is_bold = False
                for span in line['spans']:
                    bold_flag = bool(span['flags'] & 16) or 'Bold' in span['font']
                    if bold_flag:
                        combined += span['text']
                        is_bold = True
                if is_bold:
                    txt = combined.strip()
                    if txt:
                        raw.add(txt)

    doc.close()
    return raw


# ── Bước 2: Lọc fragment có nghĩa ─────────────────────────────────────────
def is_noise(text: str) -> bool:
    """Kiểm tra fragment có phải nhiễu không (quá ngắn, toàn punctuation)."""
    if text in SKIP_SET:
        return True
    if len(text) < 4:
        return True
    if SKIP_PATTERN.match(text):
        return True
    return False


def filter_fragments(raw: set) -> list:
    """Lọc, loại trừ, sắp xếp fragment dài nhất trước."""
    meaningful = set()

    counts = Counter(raw)  # not used for filtering currently but kept for analysis

    for f in raw:
        if is_noise(f):
            continue
        if f.isalpha() and len(f) <= SHORT_ALPHA_MAX:
            continue
        if f in EXCLUDE_FRAGMENTS:
            continue
        meaningful.add(f)

    # Sắp xếp dài → ngắn để ưu tiên match prefix dài nhất
    return sorted(meaningful, key=lambda f: (-len(f), f))


# ── Bước 3: Áp dụng bold vào Markdown ─────────────────────────────────────
def is_skip_line(stripped: str) -> bool:
    """Kiểm tra dòng cần bỏ qua (heading, separator, blank, URL)."""
    if not stripped:
        return True
    if stripped.startswith('##'):
        return True
    if stripped.startswith('---o0o') or stripped == '---':
        return True
    if stripped.startswith('http://') or stripped.startswith('https://'):
        return True
    return False


def apply_bold_prefix(line: str, fragments: list) -> str:
    """
    Tìm fragment đậm dài nhất khớp prefix của dòng, bọc trong **...**.
    Chỉ match ở đầu dòng (sau whitespace).
    """
    stripped = line.lstrip()
    if not stripped:
        return line

    leading_ws = line[:len(line) - len(stripped)]

    for frag in fragments:
        if stripped.startswith(frag):
            return leading_ws + '**' + frag + '**' + stripped[len(frag):]

    return line


def process_markdown(md_path: str, fragments: list) -> tuple:
    """Xử lý file markdown, trả về (nội_dung, thống_kê)."""
    lines = Path(md_path).read_text(encoding='utf-8').splitlines(keepends=True)
    output_lines = []
    stats = {
        'total': len(lines),
        'heading': 0,
        'separator': 0,
        'blank': 0,
        'url': 0,
        'bolded': 0,
    }

    for line in lines:
        text = line.rstrip('\n\r')
        stripped = text.strip()

        if is_skip_line(stripped):
            if stripped.startswith('##'):
                stats['heading'] += 1
            elif stripped.startswith('---o0o') or stripped == '---':
                stats['separator'] += 1
            elif not stripped:
                stats['blank'] += 1
            elif stripped.startswith('http'):
                stats['url'] += 1
            output_lines.append(text)
            continue

        new_text = apply_bold_prefix(text, fragments)
        if new_text != text:
            stats['bolded'] += 1
        output_lines.append(new_text)

    return '\n'.join(output_lines) + '\n', stats


# ── Main ──────────────────────────────────────────────────────────────────
def main():
    import argparse
    parser = argparse.ArgumentParser(description='Áp dụng in đậm từ PDF sang Markdown')
    parser.add_argument('output', nargs='?',
                        default=str(Path(MD_PATH).parent / 'Chanh-Kien-Va-Nghiep-bold.md'),
                        help='Đường dẫn file output (mặc định: Chanh-Kien-Va-Nghiep-bold.md)')
    args = parser.parse_args()

    output_path = args.output

    # Trích xuất
    print("🔍 Đang trích xuất chữ đậm từ PDF...", flush=True)
    raw = extract_bold_fragments(PDF_PATH)

    # Lọc
    fragments = filter_fragments(raw)
    print(f"   Bold fragments thô:    {len(raw)}")
    print(f"   Sau lọc (có nghĩa):    {len(fragments)}")

    if not fragments:
        print("⚠️  Không tìm thấy fragment hợp lệ. Thoát.")
        return

    print(f"\n🔤 Top 20 fragment dài nhất (sẽ khớp prefix):")
    for f in fragments[:20]:
        print(f"   [{len(f):3d}] {f[:80]}")

    # Xử lý
    print(f"\n✍️  Đang xử lý markdown...", flush=True)
    content, stats = process_markdown(MD_PATH, fragments)

    # Ghi
    Path(output_path).write_text(content, encoding='utf-8')

    # Báo cáo
    print(f"\n📊 Kết quả:")
    print(f"   PDF:       {PDF_PATH}")
    print(f"   Markdown:  {MD_PATH}")
    print(f"   Tổng dòng:         {stats['total']}")
    print(f"   Đã bỏ qua:")
    print(f"     - Heading (##)   {stats['heading']}")
    print(f"     - Separator      {stats['separator']}")
    print(f"     - Dòng trống     {stats['blank']}")
    print(f"     - URL            {stats['url']}")
    print(f"   ✅ Đã bôi đậm:     {stats['bolded']} dòng")
    print(f"\n📁 Output: {output_path}")


if __name__ == '__main__':
    main()
