#!/usr/bin/env python3
"""
Fix câu văn bị đứt gãy giữa các batch.

Logic:
  - Dòng cuối cùng có nội dung của batch N không kết thúc bằng dấu câu hoàn chỉnh
    (။ . ! ? " ) —) → dòng đó bị đứt.
  - Chuyển dòng bị đứt từ cuối batch N sang đầu batch N+1 (ngay sau ## PAGE X).
  - Xóa dòng bị đứt khỏi batch N.
  - Kết quả ghi vào thư mục riêng, KHÔNG đè lên file gốc.

Cách dùng:
  python3 bridge-fix.py                           # chạy thật
  python3 bridge-fix.py --dry-run                  # xem trước, không ghi
  python3 bridge-fix.py --src DIR --dst DIR        # tùy chỉnh thư mục
"""

import os, re, sys, glob, shutil

# ── config ──────────────────────────────────────────────────────
PROJ = "/home/tuan-nguyen/.openclaw/workspace/014-alahan-srilanka"
SRC_DIR = f"{PROJ}/edited/gemini-flash"
DST_DIR = f"{PROJ}/edited/gemini-flash-bridged"

DRY_RUN = "--dry-run" in sys.argv
for a in sys.argv[1:]:
    if a == "--src" and (i := sys.argv.index(a)) + 1 < len(sys.argv):
        SRC_DIR = sys.argv[i+1]
    if a == "--dst" and (i := sys.argv.index(a)) + 1 < len(sys.argv):
        DST_DIR = sys.argv[i+1]

# ── helpers ─────────────────────────────────────────────────────
MYANMAR = re.compile(r'[\u1000-\u109F]')
SENTENCE_END_RE = re.compile(r'[။.!?\)"\u201D\u2019\u201C]\s*$')
DASH_END_RE = re.compile(r'[—\\-]\s*$')
MYANMAR_CHAR_END_RE = re.compile(r'[\u1000-\u109F]\s*$')

# Mẫu dòng TOC / list item (thường hoàn chỉnh, không phải câu đứt)
TOC_ITEM_RE = re.compile(
    r'^\([\u1040-\u1049\u1000-\u1021]+\)'   # (၁), (က), (ခ) v.v.
    r'|^[\u1040-\u1049]{1,3}[။,]?\s'         # ၁။ ၁၀။ ၁၀, 
    r'|^[\(\[\{]?\d+[\)\]\}]?[။,:\s]'        # 1. 1) (1) v.v.
)

def is_truncated(line: str) -> bool:
    """Dòng có vẻ bị đứt giữa chừng?"""
    stripped = line.strip()
    if not stripped:
        return False

    # Bỏ qua TOC / list item (bắt đầu bằng số thứ tự)
    if TOC_ITEM_RE.match(stripped):
        return False

    # Kết thúc bằng dấu câu hoàn chỉnh → KHÔNG đứt
    if SENTENCE_END_RE.search(stripped):
        return False

    # Kết thúc bằng dấu gạch ngang → đứt
    if DASH_END_RE.search(stripped):
        return True

    # Kết thúc bằng ký tự Myanmar (chưa có ။) → đứt
    if MYANMAR_CHAR_END_RE.search(stripped):
        return True

    # Kết thúc bằng dấu câu Latin (. ! ?) → không đứt
    if re.search(r'[.!?]$', stripped):
        return False

    # Mặc định: không đứt (an toàn)
    return False


def get_last_content_line(lines: list) -> tuple[int | None, str | None]:
    """Trả về (index, text) của dòng cuối cùng có nội dung."""
    for i in range(len(lines) - 1, -1, -1):
        s = lines[i].strip()
        if s and not s.startswith('<!--'):  # bỏ qua comment HTML
            return i, s
    return None, None


def find_page_header(lines: list) -> int | None:
    """Tìm index của dòng ## PAGE X đầu tiên."""
    for j, line in enumerate(lines):
        if re.match(r'^##\s+PAGE\s+\d+', line.strip()):
            return j
    return None


def extract_page_start(filename: str) -> int:
    """Trích page-start từ tên file output-X-to-Y.md để sắp xếp đúng thứ tự."""
    m = re.search(r'output-(\d+)-to-(\d+)', filename)
    if m:
        return int(m.group(1))
    return 0


def extract_page_range(filename: str) -> tuple[int, int]:
    """Trích page-start, page-end từ tên file output-X-to-Y.md."""
    m = re.search(r'output-(\d+)-to-(\d+)', filename)
    if m:
        return int(m.group(1)), int(m.group(2))
    return 0, 0


def sort_by_page(files: list) -> list:
    """Sắp xếp file theo số trang bắt đầu."""
    return sorted(files, key=lambda f: extract_page_start(os.path.basename(f)))


# ── main ────────────────────────────────────────────────────────
def main():
    files = sort_by_page(glob.glob(f"{SRC_DIR}/output-*-to-*.md"))
    if not files:
        print("❌ Không tìm thấy file batch nào.")
        return

    print(f"📂 {len(files)} file batch trong {SRC_DIR}")
    print(f"📁 Output: {DST_DIR}")
    if DRY_RUN:
        print("🔍 DRY-RUN: chỉ kiểm tra, không ghi file.")
    print()

    # ── Đọc tất cả file vào memory ──
    files_data: dict[str, list[str]] = {}
    for f in files:
        try:
            with open(f, encoding='utf-8') as fh:
                files_data[f] = fh.readlines()
        except Exception as e:
            print(f"⚠️  Lỗi đọc {f}: {e}")
            files_data[f] = []

    # ── Phát hiện & xử lý ──
    bridges: list[dict] = []  # để report

    for i in range(len(files) - 1):
        cur_path = files[i]
        nxt_path = files[i + 1]

        cur_lines = files_data[cur_path]
        nxt_lines = files_data[nxt_path]

        idx_last, last_text = get_last_content_line(cur_lines)
        if idx_last is None:
            continue

        if not is_truncated(last_text):
            continue

        # ✅ Phát hiện câu bị đứt
        cur_name = os.path.basename(cur_path)
        nxt_name = os.path.basename(nxt_path)
        cur_start, cur_end = extract_page_range(cur_name)
        nxt_start, nxt_end = extract_page_range(nxt_name)

        # Tìm vị trí chèn trong file tiếp theo: sau ## PAGE X
        page_hdr_idx = find_page_header(nxt_lines)
        if page_hdr_idx is not None:
            insert_idx = page_hdr_idx + 1
            # Bỏ qua dòng trống sau header
            while insert_idx < len(nxt_lines) and not nxt_lines[insert_idx].strip():
                insert_idx += 1
        else:
            insert_idx = 0

        # Chèn dòng bị đứt vào file tiếp theo
        nxt_lines.insert(insert_idx, '\n')
        nxt_lines.insert(insert_idx, f'{last_text}\n')

        bridges.append({
            'from': cur_name,
            'to': nxt_name,
            'from_page_range': f"{cur_start}→{cur_end}",
            'to_page_range': f"{nxt_start}→{nxt_end}",
            'text': last_text,
            'remove_idx': idx_last,
        })

        print(f"  🔗 {cur_name} → {nxt_name}")
        preview = last_text[:80] + ('...' if len(last_text) > 80 else '')
        print(f"     └─ \"{preview}\"")

    # ── Ghi kết quả ──
    if bridges:
        print(f"\n📊 Tổng: {len(bridges)} cầu nối được phát hiện.")
    else:
        print("\n✅ Không phát hiện câu bị đứt nào.")

    if DRY_RUN:
        print("\n🔍 DRY-RUN hoàn tất. Không ghi file nào.")
        return

    # Xóa thư mục cũ nếu có & tạo mới
    if os.path.exists(DST_DIR):
        print(f"\n🗑️  Xóa thư mục cũ: {DST_DIR}")
        shutil.rmtree(DST_DIR)
    os.makedirs(DST_DIR, exist_ok=True)

    # Ghi từng file (đã qua xử lý hoặc nguyên bản)
    written = 0
    for cur_path in files:
        basename = os.path.basename(cur_path)
        lines = list(files_data[cur_path])

        # Nếu file này là nguồn của bridge → xóa dòng bị đứt
        for b in bridges:
            if b['from'] == basename:
                lines.pop(b['remove_idx'])
                break

        dst_path = os.path.join(DST_DIR, basename)
        with open(dst_path, 'w', encoding='utf-8') as fh:
            fh.writelines(lines)
        written += 1

    print(f"✅ Đã ghi {written} file vào: {DST_DIR}")

    # ── Tạo report JSON ──
    report_path = os.path.join(DST_DIR, "_bridge-report.json")
    import json
    with open(report_path, 'w', encoding='utf-8') as fh:
        json.dump(bridges, fh, indent=2, ensure_ascii=False)
    print(f"📋 Report JSON: {report_path}")


if __name__ == "__main__":
    main()
