"""
Sarathi-realistic synthetic captchas → dataset/synth/{text}_{id}.png
FREE / local only. Match real portal look: dense noise, green ink, strike.
"""
from __future__ import annotations

import argparse
import random
import string
from pathlib import Path

from PIL import Image, ImageDraw, ImageFont, ImageFilter, ImageEnhance

ROOT = Path(__file__).resolve().parent
OUT = ROOT / "dataset" / "synth"

CHARS = string.ascii_letters + string.digits


def random_text(length: int = 6) -> str:
    return "".join(random.choice(CHARS) for _ in range(length))


def find_font(size: int = 36):
    candidates = [
        r"C:\Windows\Fonts\arialbd.ttf",
        r"C:\Windows\Fonts\arial.ttf",
        r"C:\Windows\Fonts\calibrib.ttf",
        r"C:\Windows\Fonts\verdanab.ttf",
        r"C:\Windows\Fonts\tahoma.ttf",
        r"C:\Windows\Fonts\comic.ttf",
    ]
    random.shuffle(candidates)
    for p in candidates:
        if Path(p).is_file():
            try:
                return ImageFont.truetype(p, size)
            except OSError:
                continue
    return ImageFont.load_default()


def make_captcha(text: str, width: int = 170, height: int = 55) -> Image.Image:
    """Dense-noise green captcha similar to Sarathi portal."""
    bg = (
        random.randint(210, 235),
        random.randint(215, 240),
        random.randint(205, 230),
    )
    img = Image.new("RGB", (width, height), bg)
    px = img.load()

    # Dense multicolor salt-pepper (real std ~50–70)
    for _ in range(width * height // 2):
        x, y = random.randrange(width), random.randrange(height)
        px[x, y] = (
            random.randint(0, 255),
            random.randint(0, 255),
            random.randint(0, 255),
        )

    font = find_font(random.randint(26, 36))
    green = (
        random.randint(15, 55),
        random.randint(100, 165),
        random.randint(25, 75),
    )

    draw = ImageDraw.Draw(img)
    bbox = draw.textbbox((0, 0), text, font=font)
    tw, th = bbox[2] - bbox[0], bbox[3] - bbox[1]
    x0 = max(4, (width - tw) // 2 + random.randint(-12, 12))
    y0 = max(1, (height - th) // 2 + random.randint(-6, 6))

    x = x0
    for ch in text:
        cy = y0 + random.randint(-5, 5)
        for dx, dy in ((0, 0), (1, 0), (0, 1)):
            draw.text((x + dx, cy + dy), ch, font=font, fill=green)
        cw = draw.textbbox((0, 0), ch, font=font)[2]
        x += max(cw - 2, 7) + random.randint(-1, 3)

    # Wavy green strike through mid
    y_line = height // 2 + random.randint(-10, 10)
    for i in range(width):
        yy = y_line + int(2 * (((i // 9) % 2) * 2 - 1)) + random.randint(-1, 1)
        if 0 <= yy < height:
            draw.point((i, yy), fill=green)
            if yy + 1 < height and random.random() < 0.5:
                draw.point((i, yy + 1), fill=green)

    if random.random() < 0.4:
        img = img.filter(ImageFilter.SMOOTH)
    if random.random() < 0.35:
        img = ImageEnhance.Contrast(img).enhance(random.uniform(0.9, 1.3))
    return img


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--count", type=int, default=8000)
    ap.add_argument("--length", type=int, default=6)
    ap.add_argument("--out", type=str, default=str(OUT))
    ap.add_argument("--clear", action="store_true")
    args = ap.parse_args()

    out = Path(args.out)
    out.mkdir(parents=True, exist_ok=True)
    if args.clear:
        n = 0
        for p in out.glob("*.png"):
            p.unlink()
            n += 1
        print(f"Cleared {n} old synth files", flush=True)

    print(f"Generating {args.count} FREE local synth captchas -> {out}", flush=True)
    for i in range(args.count):
        text = random_text(args.length)
        img = make_captcha(text)
        img.save(out / f"{text}_{i:05d}.png", format="PNG")
        if (i + 1) % 500 == 0:
            print(f"  {i + 1}/{args.count}", flush=True)
    print("Done:", args.count, flush=True)


if __name__ == "__main__":
    main()
