import asyncio
import secrets
import string
import sys
from datetime import date, datetime

import typer
from sqlalchemy import text

from app.auth.security import hash_password
from app.db import AsyncSessionLocal

app = typer.Typer(help="Segunor Intel Grid admin CLI")


def _gen_password(length: int = 16) -> str:
    alphabet = string.ascii_letters + string.digits + "!@#$%^&*"
    return "".join(secrets.choice(alphabet) for _ in range(length))


@app.command("create-admin")
def create_admin(
    email: str = typer.Option(..., "--email", "-e"),
    password: str | None = typer.Option(None, "--password", "-p"),
) -> None:
    """Create an admin user. If --password is omitted, generate one and print it."""
    pwd = password or _gen_password()

    async def _run() -> None:
        async with AsyncSessionLocal() as session:
            existing = (
                await session.execute(text("SELECT 1 FROM users WHERE email = :e"), {"e": email})
            ).first()
            if existing:
                typer.echo(f"admin already exists: {email}", err=True)
                sys.exit(1)
            await session.execute(
                text(
                    """
                    INSERT INTO users (email, hashed_password, role)
                    VALUES (:e, :p, 'admin')
                    """
                ),
                {"e": email, "p": hash_password(pwd)},
            )
            await session.commit()

    asyncio.run(_run())
    typer.echo(f"admin created: {email}")
    if not password:
        typer.echo(f"password: {pwd}")


def _parse_date(s: str | None) -> date | None:
    if not s:
        return None
    return datetime.strptime(s, "%Y-%m-%d").date()


@app.command("run-scrape")
def run_scrape(
    source: str = typer.Argument(..., help="distribuicao | cire | ptdata | dre"),
    date_from: str | None = typer.Option(None, "--date-from", help="YYYY-MM-DD (distribuicao)"),
    date_to: str | None = typer.Option(None, "--date-to", help="YYYY-MM-DD (distribuicao)"),
    day: str | None = typer.Option(None, "--date", help="Shorthand: single day YYYY-MM-DD"),
    days: str = typer.Option("todos", "--days", help="cire: 15 | 30 | todos"),
) -> None:
    from app.jobs.scheduler import (
        run_cire, run_distribuicao, run_dre_fetch, run_ptdata_refresh,
    )

    if source == "distribuicao":
        df = _parse_date(day or date_from)
        dt = _parse_date(day or date_to)
        log_id = asyncio.run(run_distribuicao(df, dt))
    elif source == "cire":
        log_id = asyncio.run(run_cire(days=days))
    elif source == "ptdata":
        log_id = asyncio.run(run_ptdata_refresh())
    elif source == "dre":
        log_id = asyncio.run(run_dre_fetch())
    else:
        typer.echo(f"unknown source: {source}", err=True)
        sys.exit(1)
    typer.echo(f"done, log_id={log_id}")


@app.command("rescan-distribuicao")
def rescan_distribuicao() -> None:
    """Re-evaluate every distribuicao row against the strict matcher and delete
    rows whose parties don't pass (distintivo + corporate suffix). Use after
    tightening the matcher."""
    from app.services.cleanup import rescan_distribuicao_matches

    async def _run() -> dict:
        async with AsyncSessionLocal() as s:
            return await rescan_distribuicao_matches(s)

    result = asyncio.run(_run())
    typer.echo(f"deleted: {result['total_deleted']}")
    if result["deleted_by_company"]:
        typer.echo("top deleted:")
        for name, n in sorted(
            result["deleted_by_company"].items(), key=lambda kv: -kv[1]
        )[:10]:
            typer.echo(f"  {n:>6}  {name[:60]}")
    if result["kept_by_company"]:
        typer.echo("kept:")
        for name, n in sorted(
            result["kept_by_company"].items(), key=lambda kv: -kv[1]
        )[:10]:
            typer.echo(f"  {n:>6}  {name[:60]}")


if __name__ == "__main__":
    app()
