from __future__ import annotations

import socket
import time
from urllib.parse import quote
from typing import Any

import httpx
from flask import jsonify, g, request

from .. import settings
from .. import ariadne_client
from ..db import connect
from ..keycloak import admin_client, require_auth, require_account_access
from ..nextcloud_mail_sync import trigger as trigger_nextcloud_mail_sync
from ..utils import random_password
from ..firefly_user_sync import trigger as trigger_firefly_user_sync
from ..wger_user_sync import trigger as trigger_wger_user_sync


def _tcp_check(host: str, port: int, timeout_sec: float) -> bool:
    if not host or port <= 0:
        return False
    try:
        with socket.create_connection((host, port), timeout=timeout_sec):
            return True
    except OSError:
        return False


def register_account_actions(app) -> None:
    """Register account mutation and admin-action endpoints."""

    @app.route("/api/account/mailu/rotate", methods=["POST"])
    @require_auth
    def account_mailu_rotate() -> Any:
        """Rotate the user's Mailu app password and trigger dependent syncs."""

        ok, resp = require_account_access()
        if not ok:
            return resp
        if ariadne_client.enabled():
            return ariadne_client.proxy("POST", "/api/account/mailu/rotate")
        if not admin_client().ready():
            return jsonify({"error": "server not configured"}), 503

        username = g.keycloak_username
        if not username:
            return jsonify({"error": "missing username"}), 400

        password = random_password()
        try:
            admin_client().set_user_attribute(username, "mailu_app_password", password)
        except Exception:
            return jsonify({"error": "failed to update mail password"}), 502

        sync_enabled = bool(settings.MAILU_SYNC_URL)
        sync_ok = False
        sync_error = ""
        if sync_enabled:
            try:
                with httpx.Client(timeout=30) as client:
                    resp = client.post(
                        settings.MAILU_SYNC_URL,
                        json={"ts": int(time.time()), "wait": True, "reason": "portal_mailu_rotate"},
                    )
                    sync_ok = resp.status_code == 200
                    if not sync_ok:
                        sync_error = f"sync status {resp.status_code}"
            except Exception:
                sync_error = "sync request failed"

        nextcloud_sync: dict[str, Any] = {"status": "skipped"}
        try:
            nextcloud_sync = trigger_nextcloud_mail_sync(username, wait=True)
        except Exception:
            nextcloud_sync = {"status": "error"}

        return jsonify(
            {
                "password": password,
                "sync_enabled": sync_enabled,
                "sync_ok": sync_ok,
                "sync_error": sync_error,
                "nextcloud_sync": nextcloud_sync,
            }
        )

    @app.route("/api/account/wger/reset", methods=["POST"])
    @require_auth
    def account_wger_reset() -> Any:
        """Reset the user's Wger password through the sync Job path."""

        ok, resp = require_account_access()
        if not ok:
            return resp
        if ariadne_client.enabled():
            return ariadne_client.proxy("POST", "/api/account/wger/reset")
        if not admin_client().ready():
            return jsonify({"error": "server not configured"}), 503

        username = g.keycloak_username
        if not username:
            return jsonify({"error": "missing username"}), 400

        keycloak_email = g.keycloak_email or ""
        mailu_email = ""
        try:
            user = admin_client().find_user(username) or {}
            attrs = user.get("attributes") if isinstance(user, dict) else None
            if isinstance(attrs, dict):
                raw_mailu = attrs.get("mailu_email")
                if isinstance(raw_mailu, list) and raw_mailu:
                    mailu_email = str(raw_mailu[0])
                elif isinstance(raw_mailu, str) and raw_mailu:
                    mailu_email = raw_mailu
        except Exception:
            pass

        email = mailu_email or f"{username}@{settings.MAILU_DOMAIN}"
        password = random_password()

        try:
            result = trigger_wger_user_sync(username, email, password, wait=True)
            status_val = result.get("status") if isinstance(result, dict) else "error"
            if status_val != "ok":
                raise RuntimeError(f"wger sync {status_val}")
        except Exception as exc:
            message = str(exc).strip() or "wger sync failed"
            return jsonify({"error": message}), 502

        try:
            admin_client().set_user_attribute(username, "wger_password", password)
            admin_client().set_user_attribute(
                username,
                "wger_password_updated_at",
                time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
            )
        except Exception:
            return jsonify({"error": "failed to store wger password"}), 502

        return jsonify({"status": "ok", "password": password})

    @app.route("/api/account/wger/rotation/check", methods=["POST"])
    @require_auth
    def account_wger_rotation_check() -> Any:
        """Proxy or reject Wger rotation status checks for this account."""

        ok, resp = require_account_access()
        if not ok:
            return resp
        if ariadne_client.enabled():
            return ariadne_client.proxy("POST", "/api/account/wger/rotation/check")
        return jsonify({"error": "server not configured"}), 503

    @app.route("/api/account/firefly/reset", methods=["POST"])
    @require_auth
    def account_firefly_reset() -> Any:
        """Reset the user's Firefly password through the sync Job path."""

        ok, resp = require_account_access()
        if not ok:
            return resp
        if ariadne_client.enabled():
            return ariadne_client.proxy("POST", "/api/account/firefly/reset")
        if not admin_client().ready():
            return jsonify({"error": "server not configured"}), 503

        username = g.keycloak_username
        if not username:
            return jsonify({"error": "missing username"}), 400

        keycloak_email = g.keycloak_email or ""
        mailu_email = ""
        try:
            user = admin_client().find_user(username) or {}
            attrs = user.get("attributes") if isinstance(user, dict) else None
            if isinstance(attrs, dict):
                raw_mailu = attrs.get("mailu_email")
                if isinstance(raw_mailu, list) and raw_mailu:
                    mailu_email = str(raw_mailu[0])
                elif isinstance(raw_mailu, str) and raw_mailu:
                    mailu_email = raw_mailu
        except Exception:
            pass

        email = mailu_email or f"{username}@{settings.MAILU_DOMAIN}"
        password = random_password(24)

        try:
            result = trigger_firefly_user_sync(username, email, password, wait=True)
            status_val = result.get("status") if isinstance(result, dict) else "error"
            if status_val != "ok":
                raise RuntimeError(f"firefly sync {status_val}")
        except Exception as exc:
            message = str(exc).strip() or "firefly sync failed"
            return jsonify({"error": message}), 502

        try:
            admin_client().set_user_attribute(username, "firefly_password", password)
            admin_client().set_user_attribute(
                username,
                "firefly_password_updated_at",
                time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
            )
        except Exception:
            return jsonify({"error": "failed to store firefly password"}), 502

        return jsonify({"status": "ok", "password": password})

    @app.route("/api/account/firefly/rotation/check", methods=["POST"])
    @require_auth
    def account_firefly_rotation_check() -> Any:
        """Proxy or reject Firefly rotation status checks for this account."""

        ok, resp = require_account_access()
        if not ok:
            return resp
        if ariadne_client.enabled():
            return ariadne_client.proxy("POST", "/api/account/firefly/rotation/check")
        return jsonify({"error": "server not configured"}), 503

    @app.route("/api/account/nextcloud/mail/sync", methods=["POST"])
    @require_auth
    def account_nextcloud_mail_sync() -> Any:
        """Trigger a targeted Nextcloud mail sync for the signed-in user."""

        ok, resp = require_account_access()
        if not ok:
            return resp
        if ariadne_client.enabled():
            payload = request.get_json(silent=True) or {}
            return ariadne_client.proxy("POST", "/api/account/nextcloud/mail/sync", payload=payload)
        if not admin_client().ready():
            return jsonify({"error": "server not configured"}), 503

        username = g.keycloak_username
        if not username:
            return jsonify({"error": "missing username"}), 400

        payload = request.get_json(silent=True) or {}
        wait = bool(payload.get("wait", True))

        try:
            result = trigger_nextcloud_mail_sync(username, wait=wait)
            return jsonify(result)
        except Exception as exc:
            message = str(exc).strip() or "failed to sync nextcloud mail"
            return jsonify({"error": message}), 502
