#!/usr/bin/env python3
#
# Scan ~/webGoggles (or given path) for all session screenshots.
# For each user (site/username), pick the one with the highest
# skin-to-total pixel ratio and save it as most_skin.png
# next to their bio_screenshot.png.
#
# Usage:
#   ./pick-most-skin [--force] [path ...]
#
# If no path given, defaults to ~/webGoggles.
# Multiple paths can be specified.
#
# Requires: opencv-python (pip install opencv-python)

import os
import sys
import glob as _glob
import shutil

# If cv2 isn't on the normal path, check pipx-installed opencv-python
try:
    import cv2
    import numpy as np
except ImportError:
    _pipx_venv = os.path.expanduser(
        "~/.local/pipx/venvs/opencv-python/lib/python*/site-packages"
    )
    _matches = sorted(_glob.glob(_pipx_venv))
    if _matches:
        sys.path.insert(0, _matches[-1])
        import cv2
        import numpy as np
    else:
        print("Error: opencv-python not installed.")
        print("  pip install opencv-python")
        sys.exit(1)


# HSV ranges for skin tones (tunable)
SKIN_RANGES = [
    ((0, 20, 70), (20, 255, 255)),     # warm/peach
    ((170, 20, 70), (180, 255, 255)),   # reddish wrap-around
]


def skin_ratio(path: str) -> float:
    """Return fraction of pixels that look like skin (0.0 – 1.0)."""
    img = cv2.imread(path)
    if img is None:
        return 0.0
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    mask = np.zeros(img.shape[:2], dtype=np.uint8)
    for lower, upper in SKIN_RANGES:
        mask |= cv2.inRange(hsv, np.array(lower, dtype=np.uint8),
                            np.array(upper, dtype=np.uint8))
    return float(cv2.countNonZero(mask)) / (img.shape[0] * img.shape[1])


def find_most_skin(site_user: str) -> tuple[float, str | None]:
    """Walk sessions under site/user/, return (best_ratio, best_path)."""
    sessions_dir = os.path.join(site_user, "sessions")
    if not os.path.isdir(sessions_dir):
        return 0.0, None

    best_ratio = 0.0
    best_path = None

    for root, dirs, files in os.walk(sessions_dir):
        if "screenshot.png" not in files:
            continue
        path = os.path.join(root, "screenshot.png")
        ratio = skin_ratio(path)
        if ratio > best_ratio:
            best_ratio = ratio
            best_path = path

    return best_ratio, best_path


def main() -> None:
    args = [a for a in sys.argv[1:] if not a.startswith("-")]
    force = "--force" in sys.argv[1:]

    roots = args if args else [os.path.expanduser("~/webGoggles")]

    for root in roots:
        root = os.path.abspath(root)
        if not os.path.isdir(root):
            print(f"[pick-most-skin] Skipping {root} – not a directory")
            continue

        print(f"[pick-most-skin] Scanning {root}")

        # Walk site/user directories
        for site in sorted(os.listdir(root)):
            site_path = os.path.join(root, site)
            if not os.path.isdir(site_path):
                continue
            for user in sorted(os.listdir(site_path)):
                user_path = os.path.join(site_path, user)
                if not os.path.isdir(user_path):
                    continue
                dest = os.path.join(user_path, "most_skin.png")

                if os.path.exists(dest) and not force:
                    print(f"  {site}/{user}: most_skin.png exists (use --force to re-scan)")
                    continue

                ratio, best = find_most_skin(user_path)
                if best is None:
                    continue

                shutil.copy2(best, dest)
                print(f"  {site}/{user}: {ratio:.1%} skin -> {dest}")

        # Build/refresh GALLERY symlinks
        gallery = os.path.join(root, "GALLERY")
        os.makedirs(gallery, exist_ok=True)

        # Remove stale symlinks
        for entry in os.listdir(gallery):
            if entry == "index.html":
                continue
            entry_path = os.path.join(gallery, entry)
            if os.path.islink(entry_path) or entry.endswith("_ms.png"):
                os.unlink(entry_path)

        entries = []
        for site in sorted(os.listdir(root)):
            site_path = os.path.join(root, site)
            if not os.path.isdir(site_path):
                continue
            for user in sorted(os.listdir(site_path)):
                user_path = os.path.join(site_path, user)
                most_skin = os.path.join(user_path, "most_skin.png")
                if not os.path.isfile(most_skin):
                    continue
                link_name = f"{user}_ms.png"
                full_link = os.path.join(gallery, link_name)
                os.symlink(os.path.relpath(most_skin, gallery), full_link)
                entries.append((user, link_name))

        # Generate gallery HTML
        html_path = os.path.join(gallery, "index.html")
        count = len(entries)
        rows = "".join(
            f'    <a href="#img-{i}" class="thumb"><img src="{fn}" loading="lazy"><span>{u}</span></a>\n'
            for i, (u, fn) in enumerate(entries)
        )
        lbs = "".join(
            f'  <div id="img-{i}" class="lightbox"><a href="#"><img src="{fn}"></a></div>\n'
            for i, (u, fn) in enumerate(entries)
        )
        html = f"""<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>webGoggles Gallery</title>
<style>
  * {{ margin: 0; padding: 0; box-sizing: border-box; }}
  body {{ background: #111; color: #ccc; font: 14px/1.4 system-ui, sans-serif; padding: 20px; }}
  h1 {{ font-size: 1.2rem; margin-bottom: 16px; color: #888; font-weight: 400; }}
  .grid {{ display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }}
  .thumb {{ display: block; position: relative; border-radius: 6px; overflow: hidden; background: #1a1a1a; text-decoration: none; }}
  .thumb img {{ width: 100%; height: 260px; object-fit: cover; display: block; }}
  .thumb span {{ display: block; padding: 6px 10px; font-size: .8rem; color: #999; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }}
  .thumb:hover img {{ opacity: .85; }}
  .lightbox {{ display: none; position: fixed; inset: 0; z-index: 100; background: rgba(0,0,0,.94); align-items: center; justify-content: center; }}
  .lightbox:target {{ display: flex; }}
  .lightbox img {{ max-width: 95vw; max-height: 95vh; object-fit: contain; border-radius: 4px; cursor: zoom-out; }}
</style>
</head>
<body>
<h1>GALLERY &middot; {count} users</h1>
<div class="grid">
{rows}</div>
{lbs}<script>
document.addEventListener('keydown', e => {{
  const m = location.hash.match(/^#img-(\\d+)$/);
  if (!m) return;
  const i = +m[1], n = {count};
  if (e.key === 'ArrowRight') location.hash = '#img-' + (i + 1 < n ? i + 1 : 0);
  if (e.key === 'ArrowLeft')  location.hash = '#img-' + (i > 0 ? i - 1 : n - 1);
  if (e.key === 'Escape')     location.hash = '#';
}});
</script></body>
</html>"""
        with open(html_path, "w") as f:
            f.write(html)
        print(f"  GALLERY/index.html — {len(entries)} entries")

    print("[pick-most-skin] Done")


if __name__ == "__main__":
    main()
