"""Batch convert fearx-photos insta/*/*.jpg → sibling .webp.

Targets only externally-served thread images (`insta/*/*.jpg`), not the staging
folder `sync/insta_photos/`. Originals preserved; serve.py content-negotiation
picks the .webp variant when the caller advertises Accept: image/webp.

Params (mirrors bootcamp `make_og.py`):
  WebP quality 80, method 6, longest-side cap 1400px (no upscaling)

Idempotent: skips when .webp already exists AND is newer/equal mtime than .jpg.
Re-running picks up only new/changed sources.

Usage:
  python scripts/convert_to_webp.py            # convert with defaults
  python scripts/convert_to_webp.py --force    # rebuild every .webp
"""
from __future__ import annotations

import argparse
import glob
import os
import sys
import time
import traceback
from pathlib import Path

from PIL import Image

ROOT = Path(r'C:\fearx-photos')
PATTERN = r'C:\fearx-photos\insta\*\*.jpg'
WEBP_QUALITY = 80
WEBP_METHOD = 6
MAX_SIDE = 1400


def fit_size(w: int, h: int, cap: int) -> tuple[int, int]:
    longest = max(w, h)
    if longest <= cap:
        return (w, h)
    scale = cap / longest
    return (max(1, round(w * scale)), max(1, round(h * scale)))


def convert(jpg: Path, force: bool) -> str:
    """Return one of: 'converted' / 'skipped' / 'error:<reason>'."""
    webp = jpg.with_suffix('.webp')
    if webp.exists() and not force:
        try:
            if webp.stat().st_size > 0 and webp.stat().st_mtime >= jpg.stat().st_mtime:
                return 'skipped'
        except OSError:
            pass  # fall through to regenerate
    try:
        with Image.open(jpg) as im:
            if im.mode in ('RGBA', 'LA'):
                im = im.convert('RGB')
            elif im.mode != 'RGB':
                im = im.convert('RGB')
            new_size = fit_size(im.width, im.height, MAX_SIDE)
            if new_size != im.size:
                im = im.resize(new_size, Image.LANCZOS)
            # Atomic write: temp → rename to avoid serving torn files
            tmp = webp.with_suffix('.webp.tmp')
            im.save(tmp, format='WEBP', quality=WEBP_QUALITY, method=WEBP_METHOD)
            os.replace(tmp, webp)
        return 'converted'
    except Exception as e:
        return f'error:{type(e).__name__}:{e}'


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument('--force', action='store_true', help='rebuild even when .webp exists')
    ap.add_argument('--limit', type=int, default=0, help='for testing — process only N files')
    args = ap.parse_args()

    files = sorted(glob.glob(PATTERN))
    if args.limit:
        files = files[:args.limit]
    total = len(files)
    print(f'Found {total} jpg files under insta/*/*.jpg')

    counts = {'converted': 0, 'skipped': 0, 'error': 0}
    errors: list[tuple[str, str]] = []
    jpg_total = 0
    webp_total = 0
    started = time.time()

    for i, path in enumerate(files, 1):
        jpg = Path(path)
        result = convert(jpg, args.force)
        if result == 'converted':
            counts['converted'] += 1
            jpg_total += jpg.stat().st_size
            webp = jpg.with_suffix('.webp')
            if webp.exists():
                webp_total += webp.stat().st_size
        elif result == 'skipped':
            counts['skipped'] += 1
        else:
            counts['error'] += 1
            errors.append((path, result))

        if i % 100 == 0 or i == total:
            elapsed = time.time() - started
            print(f'  [{i}/{total}] converted={counts["converted"]} skipped={counts["skipped"]} '
                  f'error={counts["error"]} elapsed={elapsed:.1f}s', flush=True)

    elapsed = time.time() - started
    print('\n=== summary ===')
    print(f'  converted : {counts["converted"]:>5d}')
    print(f'  skipped   : {counts["skipped"]:>5d}')
    print(f'  error     : {counts["error"]:>5d}')
    print(f'  elapsed   : {elapsed:.1f}s')
    if counts['converted']:
        ratio = webp_total / jpg_total * 100 if jpg_total else 0
        print(f'  jpg sum   : {jpg_total/1024/1024:.1f} MB (converted set only)')
        print(f'  webp sum  : {webp_total/1024/1024:.1f} MB ({ratio:.1f}% of jpg, '
              f'save {(jpg_total-webp_total)/1024/1024:.1f} MB)')
    if errors:
        print('\nerrors:')
        for p, r in errors[:20]:
            print(f'  {p}: {r}')
        if len(errors) > 20:
            print(f'  ... and {len(errors)-20} more')
    return 0 if counts['error'] == 0 else 2


if __name__ == '__main__':
    sys.exit(main())
