"""
Demo 3 — Batch DOCX Normalizer
================================
Processes every DOCX file in a folder, applies a consistent margin profile
and header/footer template, and reports what it found and changed.

This is a real-world utility pattern — the kind of tool a publisher or
law firm would build to standardize a document library.

Demonstrates:
  - Processing multiple files in sequence
  - Reading and comparing existing margins before changing
  - Conditional modification (skip files that already conform)
  - Error handling per-file without aborting the batch
  - Summary report at the end
  - ssDocx_resave_full for normalization

Usage:
    python demo3_batch.py <input_folder> <output_folder> [LICENSE_KEY]

    Reads all *.docx from input_folder, writes normalized copies to output_folder.
    Output filenames match input filenames.

Example:
    python demo3_batch.py C:\\Documents\\Manuscripts C:\\Documents\\Normalized
"""

import sys
import os
import time
from pathlib import Path

DEMO_DIR = os.path.dirname(os.path.abspath(__file__))
SDK_ROOT  = os.path.join(DEMO_DIR, '..', '..')
sys.path.insert(0, os.path.join(SDK_ROOT, 'bindings', 'python'))
os.environ.setdefault('SMARTSCRIBEDOCX_DIR',
    os.path.join(SDK_ROOT, 'prebuilt', 'win-x64'))

import smartscribe_docx as ss

# ── Target margin profile ─────────────────────────────────────────────────────
# Standard manuscript: 1" all around, 0.5" H/F distance, no gutter
TARGET = {
    'top':          1440,
    'bottom':       1440,
    'left':         1440,
    'right':        1440,
    'header_dist':  720,
    'footer_dist':  720,
    'gutter':       0,
    'mirror_margins': False,
}
TOLERANCE = 72  # twips — differences smaller than this are ignored (5% of inch)

def margins_match(actual: dict) -> bool:
    """Return True if actual margins are within tolerance of TARGET."""
    for key in ('top','bottom','left','right'):
        if abs(actual[key] - TARGET[key]) > TOLERANCE:
            return False
    return True

def process_file(input_path: Path, output_path: Path) -> dict:
    """Process one file. Returns a result dict."""
    result = {
        'input':    str(input_path),
        'output':   str(output_path),
        'status':   'unknown',
        'changes':  [],
        'error':    None,
        'duration': 0.0,
    }
    t0 = time.time()
    try:
        with ss.DocxDocument(str(input_path)) as doc:
            m = doc.get_margins()
            title  = doc.get_doc_property('title') or input_path.stem
            author = doc.get_doc_property('author') or ''

            changes = []

            # Check and update margins
            if not margins_match(m):
                doc.set_margins(**TARGET)
                changes.append(f"margins: {m['left']/1440:.2f}\"x{m['top']/1440:.2f}\" -> 1.00\"x1.00\"")

            # Ensure even/odd headers are on
            if not doc.even_and_odd():
                doc.set_even_and_odd(True)
                changes.append("even/odd headers: enabled")

            # Set standard footer: page number centered
            ftr = ss.DocxDocument.build_hf_xml(False, '{PAGE}', 'center')
            doc.set_footer_xml(ss.HF_DEFAULT, ftr)
            doc.set_footer_xml(ss.HF_EVEN,    ftr)
            changes.append("footer: Page {PAGE} centered")

            # Set header: title on odd pages, author on even pages
            if title:
                hdr_odd = ss.DocxDocument.build_hf_xml(True, title[:60], 'left')
                doc.set_header_xml(ss.HF_DEFAULT, hdr_odd)
                changes.append(f"header (odd): '{title[:30]}...' left" if len(title) > 30 else f"header (odd): '{title}' left")

            if author:
                hdr_even = ss.DocxDocument.build_hf_xml(True, author[:60], 'right')
                doc.set_header_xml(ss.HF_EVEN, hdr_even)
                changes.append(f"header (even): '{author}' right")

            # Set decimal page numbering
            doc.set_page_number_format('decimal', 1)

            doc.save_as(str(output_path))

            result['status']  = 'modified' if changes else 'already_conforming'
            result['changes'] = changes

    except Exception as e:
        result['status'] = 'error'
        result['error']  = str(e)

    result['duration'] = time.time() - t0
    return result


def main():
    if len(sys.argv) < 3:
        print(f"Usage: python {os.path.basename(__file__)} <input_folder> <output_folder> [LICENSE_KEY]")
        sys.exit(1)

    input_folder  = Path(sys.argv[1])
    output_folder = Path(sys.argv[2])
    license_key   = sys.argv[3] if len(sys.argv) > 3 else None

    if not input_folder.exists():
        print(f"Error: input folder not found: {input_folder}")
        sys.exit(1)

    output_folder.mkdir(parents=True, exist_ok=True)

    # Initialize
    if license_key:
        ok = ss.init_licensed(license_key)
        if not ok:
            print("[WARNING] License key invalid — running in development mode", file=sys.stderr)

    # Find all DOCX files
    files = sorted(input_folder.glob("*.docx"))
    if not files:
        print(f"No .docx files found in {input_folder}")
        sys.exit(0)

    print(f"SmartScribe.Docx SDK v{ss.DocxDocument.version()} — Batch Normalizer")
    print(f"Input:  {input_folder}  ({len(files)} files)")
    print(f"Output: {output_folder}")
    print(f"Target: 1.00\" margins, centered page-number footer")
    print()

    results = []
    for i, f in enumerate(files, 1):
        out = output_folder / f.name
        print(f"  [{i:3d}/{len(files)}] {f.name}...", end=' ', flush=True)
        r = process_file(f, out)
        results.append(r)

        if r['status'] == 'error':
            print(f"ERROR: {r['error']}")
        elif r['status'] == 'already_conforming':
            print(f"OK (already conforming) [{r['duration']*1000:.0f}ms]")
        else:
            print(f"modified [{r['duration']*1000:.0f}ms]")
            for change in r['changes']:
                print(f"          {change}")

    # Summary
    n_mod  = sum(1 for r in results if r['status'] == 'modified')
    n_ok   = sum(1 for r in results if r['status'] == 'already_conforming')
    n_err  = sum(1 for r in results if r['status'] == 'error')
    total  = sum(r['duration'] for r in results)

    print()
    print(f"{'='*60}")
    print(f"Results: {n_mod} modified, {n_ok} already conforming, {n_err} errors")
    print(f"Total time: {total:.2f}s ({total/len(files)*1000:.0f}ms avg per file)")
    if n_err:
        print(f"\nErrors:")
        for r in results:
            if r['status'] == 'error':
                print(f"  {Path(r['input']).name}: {r['error']}")

if __name__ == '__main__':
    main()
