"""
text_to_markdown.py
-------------------
Convert plain text (from Google Drive text export) to structured Markdown.
Google Drive text export giữ đúng numbering (ĐIỀU 1., 1.1., 4.1., 5.2.1.)
trong khi DOCX export bị nhả loạn số.

Pipeline:
  1. Detect tab-separated rows → convert thành markdown tables
  2. Detect heading patterns (ĐIỀU, X.Y., X.Y.Z., ALL CAPS) → gán #/##/###
  3. Detect bullet lists (a), (b), -, • etc.
  4. Clean up formatting
"""

import re
from typing import List, Tuple


# ───────────────────────────────────────────────
# Heading patterns cho hợp đồng pháp lý VN
# ───────────────────────────────────────────────

RE_DIEU = re.compile(
    r"^((?:ĐIỀU|Điều)\s+\d+[\.\:]?\s*.*)$",
    re.UNICODE,
)

RE_CHUONG = re.compile(
    r"^((?:CHƯƠNG|Chương|PHẦN|Phần|MỤC|Mục)\s+[IVXLCDM\d]+[\.\:]?\s*.*)$",
    re.UNICODE | re.IGNORECASE,
)

# Số thứ tự điều khoản đầu dòng: "1. TÊN ĐIỀU" (H1)
# Dạng: Số. [CHỮ HOA NGUYÊN VĂN] — toàn bộ phần title phải viết hoa
RE_DIEU_SO = re.compile(
    r"^\d{1,2}\.\s+([A-ZĐÀÁẢÃẠĂẮẶẰẲẴÂẤẦẨẪẬÈÉẺẼẸÊẾỀỂỄỆÌÍỈĨỊÒÓỎÕỌÔỐỒỔỖỘƠỚỜỞỠỢÙÚỦŨỤƯỨỪỬỮỰỲÝỶỸỴ\s,\-/\(\)\d]+)$",
    re.UNICODE
)

# Roman numeral section: I., II., III., IV. ...
RE_ROMAN = re.compile(r"^((?:I|II|III|IV|V|VI|VII|VIII|IX|X)[\.\.:]\s+.+)$", re.UNICODE)

# X.Y.Z. pattern (H3) - check TRƯỚC X.Y. vì X.Y.Z cũng match X.Y
RE_H3 = re.compile(r"^(\d+\.\d+\.\d+\.?\s)", re.UNICODE)

# X.Y. pattern (H2) — chỉ match khi KHÔNG phải X.Y.Z.
RE_H2 = re.compile(r"^(\d+\.\d+\.?\s)", re.UNICODE)

# ALL CAPS heading chỉ hợp lệ nếu bắt đầu bằng từ khóa hợp đồng thực sự
RE_CAPS_CONTRACT_KEYWORDS = re.compile(
    r"^(HỢP ĐỒNG|ĐẠI DIỆN|PHỤ LỤC|BIÊN BẢN|THỎA THUẬN|CỘNG HÒA|NƯỚC)",
    re.UNICODE | re.IGNORECASE,
)


def _is_all_caps(text: str) -> bool:
    """True nếu toàn bộ chữ cái đều viết hoa."""
    letters = [c for c in text if c.isalpha()]
    return len(letters) > 3 and all(c == c.upper() for c in letters)


def _is_table_block(lines: List[str], start: int) -> Tuple[bool, int]:
    """
    Detect một block tab-separated (bảng) bắt đầu từ dòng start.
    Returns (is_table, end_index).
    Bảng = ít nhất 2 dòng liên tiếp có >= 2 tabs.
    """
    count = 0
    i = start
    while i < len(lines):
        if lines[i].count("\t") >= 2:
            count += 1
            i += 1
        else:
            break

    return count >= 2, i


def _tab_block_to_markdown_table(lines: List[str]) -> str:
    """Convert tab-separated lines thành markdown table."""
    rows = []
    max_cols = 0

    for line in lines:
        cells = [c.strip() for c in line.split("\t")]
        # Loại bỏ trailing empty cells
        while cells and not cells[-1]:
            cells.pop()
        if cells:
            rows.append(cells)
            max_cols = max(max_cols, len(cells))

    if not rows or max_cols < 2:
        return "\n".join(lines)

    # Normalize row lengths
    for row in rows:
        while len(row) < max_cols:
            row.append("")

    md_lines = []
    # Header row
    md_lines.append("| " + " | ".join(rows[0]) + " |")
    md_lines.append("| " + " | ".join(["---"] * max_cols) + " |")
    # Data rows
    for row in rows[1:]:
        md_lines.append("| " + " | ".join(row) + " |")

    return "\n".join(md_lines)


def _detect_heading(line: str) -> Tuple[int, str]:
    """
    Detect heading level từ nội dung text.
    Returns: (level, clean_text) where level=0 means not a heading.
    """
    text = line.strip()
    # Strip BOM nếu có
    text = text.lstrip('\ufeff')
    if not text or len(text) > 200:
        return 0, text

    # ── Priority 1: "ĐIỀU X." → H1 ──
    if RE_DIEU.match(text):
        return 1, text

    # ── Priority 2: "CHƯƠNG/PHẦN/MỤC" → H1 ──
    if RE_CHUONG.match(text):
        return 1, text

    # ── Priority 3: Số điều khoản đầu dòng "1. TÊN ĐIỀU" (toàn hoa) → H1 ──
    # Tự động thêm prefix "ĐIỀU" để heading rõ ràng
    if RE_DIEU_SO.match(text):
        return 1, "ĐIỀU " + text

    # ── Priority 4: Roman numeral section: I., II. → H1 (chỉ khi phần sau đầy đủ chữ hoa) ──
    if RE_ROMAN.match(text):
        title_part = re.sub(r'^(?:I{1,3}|IV|VI{0,3}|IX|X)[\.:]+\s*', '', text)
        if _is_all_caps(title_part):
            return 1, text
    # ── Priority 5: ALL CAPS short line → H1 ──
    # CHỈ match các heading hợp đồng thực sự (HỢP ĐỒNG, ĐẠI DIỆN, PHỤ LỤC...)
    # KHÔNG match tên công ty, đoạn văn ALL CAPS bình thường
    if (_is_all_caps(text)
        and len(text) < 120
        and not text.startswith("|")
        and not text.startswith("-")
        and not text.startswith("•")
        and "\t" not in text
        and RE_CAPS_CONTRACT_KEYWORDS.match(text)):
        return 1, text

    # ── Priority 6: "X.Y.Z." → H3 ──
    if RE_H3.match(text):
        return 3, text

    # ── Priority 7: "X.Y." → H2 (chỉ khi không phải X.Y.Z.) ──
    if RE_H2.match(text) and not RE_H3.match(text):
        return 2, text

    return 0, text


def _clean_line(line: str) -> str:
    """Clean up a single line: normalize tabs thành spaces cho non-table lines."""
    # Giữ nguyên nếu là table (nhiều tabs)
    if line.count("\t") >= 2:
        return line

    # Thay tabs đơn thành spaces cho readability
    return line.replace("\t", " ").strip()


def text_to_markdown(text: str) -> str:
    """
    Convert plain text (từ Google Drive text export) thành structured Markdown.

    - Detect tab-separated tables → markdown tables
    - Detect heading patterns → # / ## / ###
    - Detect bullets → - list items
    - Clean formatting
    """
    if not text or not text.strip():
        return ""

    # Strip BOM ở đầu văn bản
    text = text.lstrip('\ufeff')

    lines = text.split("\n")
    result = []
    i = 0

    while i < len(lines):
        line = lines[i]

        # ── Check tab-separated table block ──
        is_table, table_end = _is_table_block(lines, i)
        if is_table:
            table_md = _tab_block_to_markdown_table(lines[i:table_end])
            result.append("")
            result.append(table_md)
            result.append("")
            i = table_end
            continue

        # ── Clean the line ──
        cleaned = _clean_line(line)

        if not cleaned:
            result.append("")
            i += 1
            continue

        # ── Lọc page numbers / headers ──
        if re.fullmatch(r"\d{1,3}", cleaned):
            i += 1
            continue
        if re.fullmatch(r"Trang\s+\d+(/\d+)?|Page\s+\d+(/\d+)?", cleaned, re.IGNORECASE):
            i += 1
            continue

        # ── Detect heading ──
        level, text_clean = _detect_heading(cleaned)
        if level > 0:
            # Merge "ĐIỀU X." + dòng tiếp theo nếu tiếp theo là ALL CAPS title
            # (PDF scan thường tách ĐIỀU và tên điều ra 2 dòng riêng)
            if RE_DIEU.match(text_clean) and not re.search(r'[a-záàảãạăắặằẳẵâấầẩẫậéèẻẽẹêếềểễệíìỉĩịóòỏõọôốồổỗộơớờởỡợúùủũụưứừửữựýỳỷỹỵđ]', text_clean):
                # "ĐIỀU X." bare → tìm dòng kế tiếp không trống
                j = i + 1
                while j < len(lines) and not lines[j].strip():
                    j += 1
                if j < len(lines):
                    next_clean = _clean_line(lines[j])
                    next_lv, next_txt = _detect_heading(next_clean)
                    # Nếu dòng kế là ALL CAPS và KHÔNG phải heading khác → merge
                    if next_lv == 0 and _is_all_caps(next_clean) and len(next_clean) < 120:
                        text_clean = text_clean.rstrip('. ') + ". " + next_clean
                        i = j  # bỏ qua dòng đã merge
            result.append(f"{'#' * level} {text_clean}")
            i += 1
            continue

        # ── Detect bullet patterns: (a), (b), -, • ──
        if re.match(r"^\([a-z]\)\s", cleaned):
            result.append(cleaned)  # Keep as-is, already looks like a list
            i += 1
            continue

        # ── Normal text ──
        result.append(cleaned)
        i += 1

    # Clean up excessive blank lines
    md = "\n".join(result)
    while "\n\n\n" in md:
        md = md.replace("\n\n\n", "\n\n")

    return md.strip()
