from __future__ import annotations

"""
Helpers for generating fallback licences (FREE and SYSOP) and detecting SysOp accounts.
"""

import json
import sqlite3
from datetime import datetime, timezone
from pathlib import Path
from typing import Iterable, List

from ..subscription.models import SubscriptionTier, get_features_for_tier
from .license_generator import LicenseGenerator
from .crypto_manager import CryptoManager

_DEFAULT_SUPER_ADMIN = "support@web-sentinel.dev"
_LICENCE_ID_FREE = "FREE-DEFAULT-001"


def detect_sysop_accounts(auth_db_path: Path | None = None) -> List[dict]:
    """
    Inspect the local authentication database and return active SysOp accounts.

    The database stores user records with a JSON payload in the `data` column.
    """
    db_path = auth_db_path or (Path.home() / ".web-sentinel" / "auth.db")
    if not db_path.exists():
        return []

    accounts: List[dict] = []
    try:
        with sqlite3.connect(db_path) as conn:
            try:
                rows = conn.execute("SELECT data FROM users").fetchall()
            except sqlite3.DatabaseError:
                return []
    except sqlite3.Error:
        return []

    for (raw,) in rows:
        if not raw:
            continue
        try:
            payload = json.loads(raw)
        except (json.JSONDecodeError, TypeError):
            continue

        role = str(payload.get("role", "")).lower()
        is_active = payload.get("is_active", True)
        if role == "sysop" and is_active:
            accounts.append(payload)
    return accounts


def detect_active_session(session_path: Path | None = None) -> List[dict]:
    """
    Inspect the persisted session (auth-config.json).
    Returns a list containing the user payload if the session is active and remembered.
    """
    path = session_path or (Path.home() / ".web-sentinel" / "auth-config.json")
    if not path.exists():
        return []
    try:
        session_data = json.loads(path.read_text(encoding="utf-8"))
    except (json.JSONDecodeError, OSError):
        return []

    if not session_data.get("remember_me"):
        return []

    user_data = session_data.get("user_data")
    if not isinstance(user_data, dict):
        return []

    is_active = user_data.get("is_active", True)
    if not is_active:
        return []

    return [user_data]


def resolve_user_subscription_tier(email: str, db_path: Path | None = None) -> SubscriptionTier | None:
    db_path = db_path or (Path.home() / ".web-sentinel" / "auth.db")
    if not email or not db_path.exists():
        return None
    try:
        with sqlite3.connect(db_path) as conn:
            cursor = conn.execute(
                "SELECT tier FROM user_subscriptions WHERE lower(email) = ?",
                (email.lower(),),
            )
            row = cursor.fetchone()
    except sqlite3.Error:
        return None

    if not row or not row[0]:
        return None

    try:
        return SubscriptionTier(row[0].lower())
    except ValueError:
        return None


def generate_default_free_license(licence_path: Path) -> Path:
    """
    Generate (or overwrite) the default FREE licence at the provided path.
    """
    licence_path.parent.mkdir(parents=True, exist_ok=True)

    crypto = CryptoManager()
    private_key = crypto.get_private_key_path()
    generator = LicenseGenerator(private_key)

    config = LicenseGenerator.default_config(
        licence_id=_LICENCE_ID_FREE,
        tier="FREE",
        valid_until=datetime(2099, 12, 31, tzinfo=timezone.utc),
        max_users=1,
        max_domains=3,
        features={
            "basic_scan": True,
            "air_gap": True,
        },
        super_admin_email=_DEFAULT_SUPER_ADMIN,
        grace_hours=0,
    )

    generator.generate(config, licence_path)
    return licence_path


def generate_sysop_license(licence_path: Path, accounts: Iterable[dict]) -> Path:
    """
    Generate a SYSOP licence granting full access, using the first account as owner.
    """
    licence_path.parent.mkdir(parents=True, exist_ok=True)

    accounts = list(accounts)
    owner_email = _DEFAULT_SUPER_ADMIN
    if accounts:
        owner_email = accounts[0].get("email", owner_email)

    crypto = CryptoManager()
    private_key = crypto.get_private_key_path()
    generator = LicenseGenerator(private_key)

    config = LicenseGenerator.default_config(
        licence_id=f"SYSOP-{datetime.now(timezone.utc).strftime('%Y%m%d%H%M%S')}",
        tier="SYSOP",
        valid_until=datetime(2099, 12, 31, tzinfo=timezone.utc),
        max_users=-1,
        max_domains=-1,
        features={
            "invasive_tests": True,
            "html_export": True,
            "multi_user": True,
            "api_access": True,
            "advanced_reports": True,
            "air_gap": True,
        },
        super_admin_email=owner_email,
        grace_hours=0,
    )

    generator.generate(config, licence_path)
    return licence_path


def generate_license_for_tier(
    licence_path: Path,
    tier: SubscriptionTier,
    owner_email: str,
) -> Path:
    licence_path.parent.mkdir(parents=True, exist_ok=True)

    features_data = get_features_for_tier(tier)

    feature_flags = []
    if features_data.allow_invasive_tests:
        feature_flags.append("invasive_tests")
    if features_data.allow_html_export:
        feature_flags.append("html_export")
    if features_data.allow_multi_user:
        feature_flags.append("multi_user")
    if features_data.allow_api_access:
        feature_flags.append("api_access")

    feature_flags.append("air_gap")

    crypto = CryptoManager()
    private_key = crypto.get_private_key_path()
    generator = LicenseGenerator(private_key)

    config = LicenseGenerator.default_config(
        licence_id=f"{tier.value.upper()}-{datetime.now(timezone.utc).strftime('%Y%m%d%H%M%S')}",
        tier=tier.value.upper(),
        valid_until=datetime(2099, 12, 31, tzinfo=timezone.utc),
        max_users=features_data.max_users,
        max_domains=features_data.domain_limit,
        features={flag: True for flag in feature_flags},
        super_admin_email=owner_email or _DEFAULT_SUPER_ADMIN,
        grace_hours=0,
    )

    generator.generate(config, licence_path)
    return licence_path
