# retoor <retoor@molodetz.nl>

from devplacepy.database import get_table
from devplacepy.cli._shared import _audit_cli


def _remove_zip_artifacts(job):
    import shutil
    from pathlib import Path
    from devplacepy.config import ZIP_STAGING_DIR

    local_path = (job.get("result") or {}).get("local_path")
    if local_path:
        Path(local_path).unlink(missing_ok=True)
    shutil.rmtree(ZIP_STAGING_DIR / job["uid"], ignore_errors=True)


def cmd_zips_prune(args):
    from datetime import datetime, timezone
    from devplacepy.services.jobs import queue

    now = datetime.now(timezone.utc)
    removed = 0
    for job in queue.list_jobs(kind="zip", status=queue.DONE):
        expires_at = job.get("expires_at")
        if not expires_at:
            continue
        try:
            expiry = datetime.fromisoformat(expires_at)
        except (ValueError, TypeError):
            continue
        if expiry < now:
            _remove_zip_artifacts(job)
            get_table("jobs").delete(uid=job["uid"])
            removed += 1
    _audit_cli("cli.zips.prune", f"CLI pruned {removed} expired zip jobs", metadata={"count": removed})
    print(f"Pruned {removed} expired zip job(s)")


def cmd_zips_clear(args):
    from devplacepy.services.jobs import queue

    jobs = queue.list_jobs(kind="zip")
    for job in jobs:
        _remove_zip_artifacts(job)
        get_table("jobs").delete(uid=job["uid"])
    _audit_cli("cli.zips.clear", f"CLI cleared all zip jobs ({len(jobs)})", metadata={"count": len(jobs)})
    print(f"Cleared {len(jobs)} zip job(s) and their archives")


def cmd_forks_prune(args):
    from datetime import datetime, timezone
    from devplacepy.services.jobs import queue

    now = datetime.now(timezone.utc)
    removed = 0
    for job in queue.list_jobs(kind="fork", status=queue.DONE):
        expires_at = job.get("expires_at")
        if not expires_at:
            continue
        try:
            expiry = datetime.fromisoformat(expires_at)
        except (ValueError, TypeError):
            continue
        if expiry < now:
            get_table("jobs").delete(uid=job["uid"])
            removed += 1
    _audit_cli("cli.forks.prune", f"CLI pruned {removed} expired fork jobs", metadata={"count": removed})
    print(f"Pruned {removed} expired fork job(s)")


def cmd_forks_clear(args):
    from devplacepy.services.jobs import queue

    jobs = queue.list_jobs(kind="fork")
    for job in jobs:
        get_table("jobs").delete(uid=job["uid"])
    _audit_cli("cli.forks.clear", f"CLI cleared all fork jobs ({len(jobs)})", metadata={"count": len(jobs)})
    print(f"Cleared {len(jobs)} fork job(s)")


def _remove_seo_artifacts(job):
    import shutil
    from devplacepy.config import SEO_REPORTS_DIR

    shutil.rmtree(SEO_REPORTS_DIR / job["uid"], ignore_errors=True)


def cmd_seo_prune(args):
    from datetime import datetime, timezone
    from devplacepy.services.jobs import queue

    now = datetime.now(timezone.utc)
    removed = 0
    for job in queue.list_jobs(kind="seo", status=queue.DONE):
        expires_at = job.get("expires_at")
        if not expires_at:
            continue
        try:
            expiry = datetime.fromisoformat(expires_at)
        except (ValueError, TypeError):
            continue
        if expiry < now:
            _remove_seo_artifacts(job)
            get_table("jobs").delete(uid=job["uid"])
            removed += 1
    _audit_cli("cli.seo.prune", f"CLI pruned {removed} expired SEO jobs", metadata={"count": removed})
    print(f"Pruned {removed} expired SEO audit(s)")


def cmd_seo_clear(args):
    from devplacepy.services.jobs import queue

    jobs = queue.list_jobs(kind="seo")
    for job in jobs:
        _remove_seo_artifacts(job)
        get_table("jobs").delete(uid=job["uid"])
    _audit_cli("cli.seo.clear", f"CLI cleared all SEO jobs ({len(jobs)})", metadata={"count": len(jobs)})
    print(f"Cleared {len(jobs)} SEO audit(s) and their reports")


def cmd_seo_meta_prune(args):
    from datetime import datetime, timezone
    from devplacepy.services.jobs import queue

    now = datetime.now(timezone.utc)
    removed = 0
    for job in queue.list_jobs(kind="seo_meta", status=queue.DONE):
        expires_at = job.get("expires_at")
        if not expires_at:
            continue
        try:
            expiry = datetime.fromisoformat(expires_at)
        except (ValueError, TypeError):
            continue
        if expiry < now:
            get_table("jobs").delete(uid=job["uid"])
            removed += 1
    _audit_cli(
        "cli.seo_meta.prune",
        f"CLI pruned {removed} expired SEO metadata jobs",
        metadata={"count": removed},
    )
    print(f"Pruned {removed} expired SEO metadata job(s)")


def cmd_seo_meta_clear(args):
    from devplacepy.services.jobs import queue

    jobs = queue.list_jobs(kind="seo_meta")
    for job in jobs:
        get_table("jobs").delete(uid=job["uid"])
    _audit_cli(
        "cli.seo_meta.clear",
        f"CLI cleared all SEO metadata jobs ({len(jobs)})",
        metadata={"count": len(jobs)},
    )
    print(f"Cleared {len(jobs)} SEO metadata job(s); generated metadata persists")


def _remove_deepsearch_artifacts(job):
    import shutil
    from devplacepy.config import DEEPSEARCH_DIR
    from devplacepy.services.deepsearch.store import VectorStore

    uid = job["uid"]
    collection = f"ds_{uid.replace('-', '')}"
    VectorStore(collection).drop()
    shutil.rmtree(DEEPSEARCH_DIR / uid, ignore_errors=True)


def cmd_deepsearch_prune(args):
    from datetime import datetime, timezone
    from devplacepy.services.jobs import queue

    now = datetime.now(timezone.utc)
    removed = 0
    for job in queue.list_jobs(kind="deepsearch", status=queue.DONE):
        expires_at = job.get("expires_at")
        if not expires_at:
            continue
        try:
            expiry = datetime.fromisoformat(expires_at)
        except (ValueError, TypeError):
            continue
        if expiry < now:
            _remove_deepsearch_artifacts(job)
            get_table("jobs").delete(uid=job["uid"])
            removed += 1
    _audit_cli(
        "cli.deepsearch.prune",
        f"CLI pruned {removed} expired DeepSearch jobs",
        metadata={"count": removed},
    )
    print(f"Pruned {removed} expired DeepSearch job(s)")


def cmd_deepsearch_clear(args):
    from devplacepy.services.jobs import queue

    jobs = queue.list_jobs(kind="deepsearch")
    for job in jobs:
        _remove_deepsearch_artifacts(job)
        get_table("jobs").delete(uid=job["uid"])
    _audit_cli(
        "cli.deepsearch.clear",
        f"CLI cleared all DeepSearch jobs ({len(jobs)})",
        metadata={"count": len(jobs)},
    )
    print(f"Cleared {len(jobs)} DeepSearch job(s) and their collections")


def cmd_isslop_prune(args):
    from datetime import datetime, timezone
    from devplacepy.services.jobs import queue

    now = datetime.now(timezone.utc)
    removed = 0
    for job in queue.list_jobs(kind="isslop", status=queue.DONE):
        expires_at = job.get("expires_at")
        if not expires_at:
            continue
        try:
            expiry = datetime.fromisoformat(expires_at)
        except (ValueError, TypeError):
            continue
        if expiry < now:
            get_table("jobs").delete(uid=job["uid"])
            removed += 1
    _audit_cli("cli.isslop.prune", f"CLI pruned {removed} expired AI usage analysis jobs", metadata={"count": removed})
    print(f"Pruned {removed} expired AI usage analysis job(s) (reports persist)")


def cmd_isslop_clear(args):
    from devplacepy.services.jobs import queue
    from devplacepy.services.jobs.isslop import store

    jobs = queue.list_jobs(kind="isslop")
    for job in jobs:
        get_table("jobs").delete(uid=job["uid"])
    analyses = list(get_table(store.TABLE_ANALYSES).find())
    for analysis in analyses:
        store.purge_analysis(analysis["uid"])
    _audit_cli(
        "cli.isslop.clear",
        f"CLI cleared {len(analyses)} AI usage analyses and {len(jobs)} job rows",
        metadata={"analyses": len(analyses), "jobs": len(jobs)},
    )
    print(f"Cleared {len(analyses)} AI usage analysis(es), their reports and {len(jobs)} job row(s)")


def cmd_isslop_analyze(args):
    import asyncio

    from devplacepy.config import ISSLOP_WORKSPACES_DIR, ensure_data_dirs
    from devplacepy.database import INTERNAL_GATEWAY_URL, internal_gateway_key
    from devplacepy.models import IsslopRunForm
    from devplacepy.services.jobs.isslop import store
    from devplacepy.services.jobs.isslop.acquisition.workspace import remove_workspace, workspace_for
    from devplacepy.services.jobs.isslop.config import settings_from_payload
    from devplacepy.services.jobs.isslop.events import KIND_DONE, KIND_ERROR
    from devplacepy.services.jobs.isslop.persistence import EventPersister
    from devplacepy.services.jobs.isslop.pipeline import run_pipeline
    from devplacepy.utils import generate_uid

    url = IsslopRunForm(url=args.url).url
    ensure_data_dirs()
    uid = generate_uid()
    settings = settings_from_payload(
        {
            "url": url,
            "llm_endpoint": INTERNAL_GATEWAY_URL,
            "api_key": internal_gateway_key(),
            "allow_private": bool(args.allow_private),
            "media_dir": str(store.media_dir_for(uid)),
        }
    )
    store.create_analysis(uid, url, "system", "cli")
    persister = EventPersister(uid)
    store.update_analysis(uid, status="running")
    workspace = workspace_for(ISSLOP_WORKSPACES_DIR, url, uid)

    async def run() -> int:
        failed = False
        try:
            async for event in run_pipeline(url, workspace, settings):
                persister.apply(event)
                if args.json:
                    print(event.to_json(), flush=True)
                else:
                    print(f"[{event.kind}] {event.message}", flush=True)
                if event.kind == KIND_ERROR:
                    failed = True
                if event.kind == KIND_DONE and not args.json:
                    print(f"Report: /tools/isslop/{uid}/report")
                    print(f"Badge:  /tools/isslop/{uid}/badge.svg")
        finally:
            remove_workspace(workspace)
        return 1 if failed else 0

    exit_code = asyncio.run(run())
    _audit_cli(
        "cli.isslop.analyze",
        f"CLI AI usage analysis of {url}",
        metadata={"uid": uid, "failed": bool(exit_code)},
    )
    raise SystemExit(exit_code)


def register_jobs(subparsers):
    zips = subparsers.add_parser("zips", help="Zip archive job management")
    zips_sub = zips.add_subparsers(title="action", dest="action")
    zips_prune = zips_sub.add_parser(
        "prune", help="Delete expired zip archives and their job rows"
    )
    zips_prune.set_defaults(func=cmd_zips_prune)
    zips_clear = zips_sub.add_parser(
        "clear", help="Delete every zip archive and job row"
    )
    zips_clear.set_defaults(func=cmd_zips_clear)

    forks = subparsers.add_parser("forks", help="Fork job management")
    forks_sub = forks.add_subparsers(title="action", dest="action")
    forks_prune = forks_sub.add_parser(
        "prune", help="Delete expired completed fork job rows (forked projects persist)"
    )
    forks_prune.set_defaults(func=cmd_forks_prune)
    forks_clear = forks_sub.add_parser(
        "clear", help="Delete every fork job row (forked projects persist)"
    )
    forks_clear.set_defaults(func=cmd_forks_clear)

    seo = subparsers.add_parser("seo", help="SEO Diagnostics job management")
    seo_sub = seo.add_subparsers(title="action", dest="action")
    seo_prune = seo_sub.add_parser(
        "prune", help="Delete expired SEO audit reports and their job rows"
    )
    seo_prune.set_defaults(func=cmd_seo_prune)
    seo_clear = seo_sub.add_parser(
        "clear", help="Delete every SEO audit report and job row"
    )
    seo_clear.set_defaults(func=cmd_seo_clear)

    seo_meta = subparsers.add_parser("seo-meta", help="SEO metadata job management")
    seo_meta_sub = seo_meta.add_subparsers(title="action", dest="action")
    seo_meta_prune = seo_meta_sub.add_parser(
        "prune", help="Delete expired SEO metadata job rows (generated metadata persists)"
    )
    seo_meta_prune.set_defaults(func=cmd_seo_meta_prune)
    seo_meta_clear = seo_meta_sub.add_parser(
        "clear", help="Delete every SEO metadata job row (generated metadata persists)"
    )
    seo_meta_clear.set_defaults(func=cmd_seo_meta_clear)

    deepsearch = subparsers.add_parser("deepsearch", help="DeepSearch job management")
    deepsearch_sub = deepsearch.add_subparsers(title="action", dest="action")
    deepsearch_prune = deepsearch_sub.add_parser(
        "prune", help="Delete expired DeepSearch sessions and their job rows"
    )
    deepsearch_prune.set_defaults(func=cmd_deepsearch_prune)
    deepsearch_clear = deepsearch_sub.add_parser(
        "clear", help="Delete every DeepSearch session and job row"
    )
    deepsearch_clear.set_defaults(func=cmd_deepsearch_clear)

    isslop = subparsers.add_parser("isslop", help="AI Usage Analyzer job management")
    isslop_sub = isslop.add_subparsers(title="action", dest="action")
    isslop_prune = isslop_sub.add_parser(
        "prune", help="Delete expired AI usage analysis job rows (analyses and reports persist)"
    )
    isslop_prune.set_defaults(func=cmd_isslop_prune)
    isslop_clear = isslop_sub.add_parser(
        "clear", help="Delete every AI usage analysis, its report and job rows"
    )
    isslop_clear.set_defaults(func=cmd_isslop_clear)
    isslop_analyze = isslop_sub.add_parser(
        "analyze", help="Run a AI usage analysis from the terminal and persist its report"
    )
    isslop_analyze.add_argument("url", help="Repository or website URL to classify")
    isslop_analyze.add_argument("--json", action="store_true", help="Emit raw JSON events")
    isslop_analyze.add_argument("--allow-private", action="store_true", dest="allow_private", help="Permit private and loopback hosts")
    isslop_analyze.set_defaults(func=cmd_isslop_analyze)
