from __future__ import annotations

import re
import time
from typing import Any

from . import settings
from .k8s import get_json, post_json


def _safe_name_fragment(value: str, max_len: int = 24) -> str:
    cleaned = re.sub(r"[^a-z0-9-]+", "-", (value or "").lower()).strip("-")
    if not cleaned:
        cleaned = "user"
    return cleaned[:max_len].rstrip("-") or "user"


def _job_from_cronjob(
    cronjob: dict[str, Any],
    username: str,
    email: str,
    password: str,
) -> dict[str, Any]:
    """Render a one-off Wger user sync Job from the managed CronJob template."""

    spec = cronjob.get("spec") if isinstance(cronjob.get("spec"), dict) else {}
    jt = spec.get("jobTemplate") if isinstance(spec.get("jobTemplate"), dict) else {}
    job_spec = jt.get("spec") if isinstance(jt.get("spec"), dict) else {}

    now = int(time.time())
    safe_user = _safe_name_fragment(username)
    job_name = f"wger-user-sync-{safe_user}-{now}"

    job: dict[str, Any] = {
        "apiVersion": "batch/v1",
        "kind": "Job",
        "metadata": {
            "name": job_name,
            "namespace": settings.WGER_NAMESPACE,
            "labels": {
                "app": "wger-user-sync",
                "atlas.bstein.dev/trigger": "portal",
                "atlas.bstein.dev/username": safe_user,
            },
        },
        "spec": job_spec,
    }

    tpl = job.get("spec", {}).get("template", {})
    pod_spec = tpl.get("spec") if isinstance(tpl.get("spec"), dict) else {}
    containers = pod_spec.get("containers") if isinstance(pod_spec.get("containers"), list) else []
    if containers and isinstance(containers[0], dict):
        env = containers[0].get("env")
        if not isinstance(env, list):
            env = []
        env = [
            e
            for e in env
            if not (
                isinstance(e, dict)
                and e.get("name") in {"WGER_USERNAME", "WGER_EMAIL", "WGER_PASSWORD"}
            )
        ]
        env.append({"name": "WGER_USERNAME", "value": username})
        env.append({"name": "WGER_EMAIL", "value": email})
        env.append({"name": "WGER_PASSWORD", "value": password})
        containers[0]["env"] = env
        pod_spec["containers"] = containers
        tpl["spec"] = pod_spec
        job["spec"]["template"] = tpl

    return job


def _job_succeeded(job: dict[str, Any]) -> bool:
    """Return whether Kubernetes reports the sync Job as successfully complete."""

    status = job.get("status") if isinstance(job.get("status"), dict) else {}
    if int(status.get("succeeded") or 0) > 0:
        return True
    conditions = status.get("conditions") if isinstance(status.get("conditions"), list) else []
    for cond in conditions:
        if not isinstance(cond, dict):
            continue
        if cond.get("type") == "Complete" and cond.get("status") == "True":
            return True
    return False


def _job_failed(job: dict[str, Any]) -> bool:
    """Return whether Kubernetes reports the sync Job as failed."""

    status = job.get("status") if isinstance(job.get("status"), dict) else {}
    if int(status.get("failed") or 0) > 0:
        return True
    conditions = status.get("conditions") if isinstance(status.get("conditions"), list) else []
    for cond in conditions:
        if not isinstance(cond, dict):
            continue
        if cond.get("type") == "Failed" and cond.get("status") == "True":
            return True
    return False


def trigger(username: str, email: str, password: str, wait: bool = True) -> dict[str, Any]:
    """Start the Wger sync Job for one user and optionally wait for completion.

    WHY: account actions need an immediate per-user repair path without
    mutating the reusable CronJob template that Flux owns.
    """

    username = (username or "").strip()
    if not username:
        raise RuntimeError("missing username")
    if not password:
        raise RuntimeError("missing password")

    namespace = settings.WGER_NAMESPACE
    cronjob_name = settings.WGER_USER_SYNC_CRONJOB
    if not namespace or not cronjob_name:
        raise RuntimeError("wger sync not configured")

    cronjob = get_json(f"/apis/batch/v1/namespaces/{namespace}/cronjobs/{cronjob_name}")
    job_payload = _job_from_cronjob(cronjob, username, email, password)
    created = post_json(f"/apis/batch/v1/namespaces/{namespace}/jobs", job_payload)

    job_name = (
        created.get("metadata", {}).get("name")
        if isinstance(created.get("metadata"), dict)
        else job_payload.get("metadata", {}).get("name")
    )
    if not isinstance(job_name, str) or not job_name:
        raise RuntimeError("job name missing")

    if not wait:
        return {"job": job_name, "status": "queued"}

    deadline = time.time() + float(settings.WGER_USER_SYNC_WAIT_TIMEOUT_SEC)
    last_state = "running"
    while time.time() < deadline:
        job = get_json(f"/apis/batch/v1/namespaces/{namespace}/jobs/{job_name}")
        if _job_succeeded(job):
            return {"job": job_name, "status": "ok"}
        if _job_failed(job):
            return {"job": job_name, "status": "error"}
        time.sleep(2)
        last_state = "running"

    return {"job": job_name, "status": last_state}
