"""Central entitlement gate for CLI command execution."""

from __future__ import annotations

import os
from typing import Any

import click

from g_gremlin.credentials import metering
from g_gremlin.credentials.entitlements import get_cli_entitlements_config


def _upgrade_url() -> str:
    return os.getenv("FOUNDRYOPS_UPGRADE_URL", "https://foundryops.io/pricing")


def _plan_display_name(plan: str | None) -> str:
    config = get_cli_entitlements_config()
    if not plan:
        return "Local Free"
    return config.tier_labels.get(plan, plan)


def _fallback_tip(fallback_mode: str | None) -> str | None:
    mode = (fallback_mode or "none").strip().lower()
    if mode == "dry_run":
        return "Run with --dry-run to preview changes without writes."
    if mode == "local_only":
        return "Use a local-only mode where available."
    if mode == "preview_only":
        return "Use plan/validate preview commands on Local Free."
    return None


def _raise_paywall_error(
    capability: str,
    current_plan: str | None,
    fallback_mode: str | None,
) -> None:
    config = get_cli_entitlements_config()
    plans = config.plans_for_capability(capability)
    if plans:
        plans_display = ", ".join(config.tier_labels.get(p, p) for p in plans)
    else:
        plans_display = "Contact support"

    lines = [
        f"This command requires capability: {capability}",
        f"Plan required: {plans_display}",
        f"Current plan: {_plan_display_name(current_plan)}",
    ]
    tip = _fallback_tip(fallback_mode)
    if tip:
        lines.append(f"Tip: {tip}")
    if not current_plan or current_plan == "local_free":
        lines.append("Start a free trial: g-gremlin auth login")
    lines.append(f"Upgrade: {_upgrade_url()}")
    click.echo("Error: " + "\n".join(lines), err=True)
    raise click.exceptions.Exit(2)


def _raise_meter_error(
    meter_key: str,
    meter_result: metering.MeterReserveResult,
    current_plan: str | None,
) -> None:
    used = meter_result.used
    cap = meter_result.cap
    cap_text = "unlimited" if cap is None else str(cap)
    lines = [
        f"Limit reached: {meter_key}",
        f"Usage: {used:,} / {cap_text}",
        f"Current plan: {_plan_display_name(current_plan)}",
    ]
    if meter_result.reset_at:
        lines.append(f"Resets: {meter_result.reset_at}")
    lines.append(f"Upgrade: {_upgrade_url()}")
    click.echo("Error: " + "\n".join(lines), err=True)
    raise click.exceptions.Exit(2)


def entitlement_gate(
    cmd_id: str,
    safety: dict[str, Any],
    license_result: Any,
) -> None:
    """Run capability and meter checks for one command before execution."""
    config = get_cli_entitlements_config()

    required_capability = safety.get("required_capability")
    fallback_mode = safety.get("fallback_mode")

    entitlements = dict(getattr(license_result, "entitlements", {}) or {})
    limits = dict(getattr(license_result, "limits", {}) or {})
    current_plan = getattr(license_result, "plan", None)
    license_id = str(getattr(license_result, "license_id", "local_free") or "local_free")

    if required_capability:
        allowed = bool(entitlements.get(required_capability, False))
        if not allowed:
            _raise_paywall_error(
                capability=str(required_capability),
                current_plan=current_plan,
                fallback_mode=fallback_mode,
            )

    meter_keys = [str(m) for m in (safety.get("meters") or [])]
    for meter_key in meter_keys:
        meter_def = config.limits.get(meter_key)
        if meter_def is None:
            continue

        cap = limits.get(meter_key)
        period = meter_def.period

        # Static policy limits are not cumulative counters in v1.
        if period == "static":
            continue

        if meter_def.meter_type == "per_attempt":
            meter_result = metering.reserve_meter(
                meter_key=meter_key,
                cap=cap,
                period=period,
                license_id=license_id,
                amount=1,
            )
        else:
            meter_result = metering.check_headroom(
                meter_key=meter_key,
                cap=cap,
                period=period,
                license_id=license_id,
            )

        if not meter_result.allowed:
            _raise_meter_error(
                meter_key=meter_key,
                meter_result=meter_result,
                current_plan=current_plan,
            )


def record_post_exec(
    safety: dict[str, Any],
    license_result: Any,
    meter_amounts: dict[str, int],
) -> None:
    """
    Record post-execution volume meters for a command.

    meter_amounts maps meter key -> amount observed for this command execution.
    """
    if not meter_amounts:
        return

    config = get_cli_entitlements_config()
    limits = dict(getattr(license_result, "limits", {}) or {})
    license_id = str(getattr(license_result, "license_id", "local_free") or "local_free")

    for meter_key, amount in meter_amounts.items():
        meter_def = config.limits.get(meter_key)
        if meter_def is None:
            continue
        if meter_def.meter_type != "per_volume":
            continue
        if meter_def.period == "static":
            continue
        metering.record_volume(
            meter_key=meter_key,
            amount=max(0, int(amount)),
            period=meter_def.period,
            license_id=license_id,
            cap=limits.get(meter_key),
        )
