#!/usr/bin/env python3
"""odysseus-signature — shell wrapper for stored email signature images.

The web UI lets you draw a signature; the result lives as a PNG (and
optional SVG) in the `signatures` table, keyed by id + owner.

    odysseus-signature list                      # all signatures (metadata only)
    odysseus-signature show SIG_ID               # full record incl. data_png
    odysseus-signature export SIG_ID --png OUT   # write PNG bytes to a file
    odysseus-signature delete SIG_ID
"""

from __future__ import annotations
import sys
import os, sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "_lib"))
from cli import quiet_logs, emit, fail, common_parser, run, REPO_ROOT as _REPO_ROOT
quiet_logs()

import argparse, base64, json, logging, os, sys
from pathlib import Path

try:
    from sqlalchemy import text
    from core.database import engine
    quiet_logs()
except ModuleNotFoundError as e:
    sys.stderr.write(f"error: {e}\nhint: run from repo root with venv active.\n")
    sys.exit(2)


def _decode_png_data(data_png: str) -> bytes:
    raw = data_png or ""
    if "," in raw:
        raw = raw.split(",", 1)[1]
    try:
        decoded = base64.b64decode(raw, validate=True)
    except Exception as e:
        fail(f"data_png is not valid base64: {e}")
    if not decoded.startswith(b"\x89PNG\r\n\x1a\n"):
        fail("data_png is not a PNG image")
    return decoded


def cmd_list(args):
    """No `Signature` SQLAlchemy model is registered for the
    `signatures` table — query via raw SQL so we don't depend on it."""
    with engine.connect() as conn:
        rows = conn.execute(text(
            "SELECT id, owner, name, width, height, "
            "       length(data_png) AS png_len, "
            "       svg IS NOT NULL AS has_svg, "
            "       created_at "
            "FROM signatures ORDER BY created_at DESC"
        )).mappings().all()
    out = [
        {
            "id": r["id"],
            "owner": r["owner"] or "",
            "name": r["name"],
            "width": r["width"],
            "height": r["height"],
            "png_bytes_approx": r["png_len"],
            "has_svg": bool(r["has_svg"]),
            "created_at": str(r["created_at"] or ""),
        } for r in rows
    ]
    emit(out, args)


def cmd_show(args):
    with engine.connect() as conn:
        row = conn.execute(text(
            "SELECT id, owner, name, width, height, data_png, svg, created_at "
            "FROM signatures WHERE id = :id"
        ), {"id": args.id}).mappings().first()
    if not row:
        fail(f"no signature with id {args.id!r}")
    emit({
        "id": row["id"],
        "owner": row["owner"] or "",
        "name": row["name"],
        "width": row["width"],
        "height": row["height"],
        "data_png": row["data_png"],
        "has_svg": bool(row["svg"]),
        "created_at": str(row["created_at"] or ""),
    }, args)


def cmd_export(args):
    """Decode the data_png column to bytes and write to `--png OUT`.
    `data_png` is stored as a data URL (`data:image/png;base64,...`).
    We strip the prefix, base64-decode, and write the bytes."""
    with engine.connect() as conn:
        row = conn.execute(text(
            "SELECT data_png FROM signatures WHERE id = :id"
        ), {"id": args.id}).mappings().first()
    if not row:
        fail(f"no signature with id {args.id!r}")
    png_bytes = _decode_png_data(row["data_png"] or "")
    out = Path(args.png)
    out.parent.mkdir(parents=True, exist_ok=True)
    out.write_bytes(png_bytes)
    emit({"ok": True, "id": args.id, "path": str(out), "bytes": len(png_bytes)}, args)


def cmd_delete(args):
    with engine.begin() as conn:
        res = conn.execute(text("DELETE FROM signatures WHERE id = :id"), {"id": args.id})
        if res.rowcount == 0:
            fail(f"no signature with id {args.id!r}")
    emit({"ok": True, "id": args.id, "deleted": True}, args)


def _build_parser():
    common = argparse.ArgumentParser(add_help=False)
    common.add_argument("--pretty", action="store_true")
    p = argparse.ArgumentParser(prog="odysseus-signature", parents=[common])
    sub = p.add_subparsers(dest="cmd", required=True)

    pl = sub.add_parser("list", parents=[common])
    pl.set_defaults(func=cmd_list)

    psh = sub.add_parser("show", parents=[common])
    psh.add_argument("id")
    psh.set_defaults(func=cmd_show)

    pe = sub.add_parser("export", parents=[common])
    pe.add_argument("id")
    pe.add_argument("--png", required=True, help="output PNG path")
    pe.set_defaults(func=cmd_export)

    pd = sub.add_parser("delete", parents=[common])
    pd.add_argument("id")
    pd.set_defaults(func=cmd_delete)

    return p


if __name__ == "__main__":
    sys.exit(run(_build_parser()))
