"""Automation Profile Precedence Chain for CleverAgents v3.5.

Implements and validates the four-level precedence chain for automation
profile resolution:

    plan > action > project > global

This module provides a dedicated, testable implementation of the precedence
chain that is independent of the full ``AutomationProfileService`` CRUD
operations.  It is the canonical source of truth for precedence resolution
in plan execution contexts.

Precedence Rules
----------------

1. **Plan-level** — explicitly set via ``--automation-profile`` on plan use.
   Highest priority; overrides action, project, and global.
2. **Action-level** — default profile set on the action template.
   Overrides project and global; used when no plan-level override is set.
3. **Project-level** — default profile set at the project level.
   Overrides global; used when neither plan nor action override is set.
4. **Global-level** — set via config key or
   ``CLEVERAGENTS_AUTOMATION_PROFILE`` env var, falling back to ``"manual"``.
   Used when none of plan, action, or project override is set.

All 16 Combinations
-------------------

The precedence chain covers all 16 combinations of:
(plan set/unset) x (action set/unset) x (project set/unset) x (global set/default)

+-------+--------+---------+--------+------------------+
| plan  | action | project | global | resolved source  |
+=======+========+=========+========+==================+
| set   | set    | set     | set    | plan             |
+-------+--------+---------+--------+------------------+
| set   | set    | set     | default| plan             |
+-------+--------+---------+--------+------------------+
| set   | set    | unset   | set    | plan             |
+-------+--------+---------+--------+------------------+
| set   | set    | unset   | default| plan             |
+-------+--------+---------+--------+------------------+
| set   | unset  | set     | set    | plan             |
+-------+--------+---------+--------+------------------+
| set   | unset  | set     | default| plan             |
+-------+--------+---------+--------+------------------+
| set   | unset  | unset   | set    | plan             |
+-------+--------+---------+--------+------------------+
| set   | unset  | unset   | default| plan             |
+-------+--------+---------+--------+------------------+
| unset | set    | set     | set    | action           |
+-------+--------+---------+--------+------------------+
| unset | set    | set     | default| action           |
+-------+--------+---------+--------+------------------+
| unset | set    | unset   | set    | action           |
+-------+--------+---------+--------+------------------+
| unset | set    | unset   | default| action           |
+-------+--------+---------+--------+------------------+
| unset | unset  | set     | set    | project          |
+-------+--------+---------+--------+------------------+
| unset | unset  | set     | default| project          |
+-------+--------+---------+--------+------------------+
| unset | unset  | unset   | set    | global           |
+-------+--------+---------+--------+------------------+
| unset | unset  | unset   | default| global (manual)  |
+-------+--------+---------+--------+------------------+

Based on ``docs/specification.md`` Section "Automation Profiles".
"""

from __future__ import annotations

import logging
import os
from dataclasses import dataclass
from enum import StrEnum

from cleveragents.domain.models.core.automation_profile import (
    BUILTIN_PROFILES,
    AutomationProfile,
)

logger = logging.getLogger(__name__)

_ENV_VAR = "CLEVERAGENTS_AUTOMATION_PROFILE"
_DEFAULT_GLOBAL_PROFILE = "manual"


class PrecedenceSource(StrEnum):
    """Indicates which level of the precedence chain resolved the profile.

    Values correspond to the four levels of the plan > action > project > global
    chain.
    """

    PLAN = "plan"
    ACTION = "action"
    PROJECT = "project"
    GLOBAL = "global"


@dataclass(frozen=True)
class PrecedenceResolution:
    """Result of a precedence chain resolution.

    Attributes:
        profile: The resolved ``AutomationProfile``.
        source: Which level of the chain provided the profile.
        profile_name: The resolved profile name string.
        plan_profile: The plan-level override (may be ``None``).
        action_profile: The action-level override (may be ``None``).
        project_profile: The project-level override (may be ``None``).
        global_profile: The effective global profile name used as fallback.
    """

    profile: AutomationProfile
    source: PrecedenceSource
    profile_name: str
    plan_profile: str | None
    action_profile: str | None
    project_profile: str | None
    global_profile: str


def _resolve_global_profile(
    global_override: str | None,
) -> str:
    """Resolve the effective global profile name.

    Precedence within global resolution:
    1. Explicit ``global_override`` argument (from config service).
    2. ``CLEVERAGENTS_AUTOMATION_PROFILE`` environment variable.
    3. Hard-coded default ``"manual"``.

    Args:
        global_override: Explicit global profile name from config, or
            ``None`` to fall back to env var / default.

    Returns:
        The effective global profile name (always a non-empty string).
    """
    if global_override and global_override.strip():
        return global_override.strip()
    env_val = os.environ.get(_ENV_VAR, "").strip()
    if env_val:
        return env_val
    return _DEFAULT_GLOBAL_PROFILE


def resolve_precedence_chain(
    *,
    plan_profile: str | None = None,
    action_profile: str | None = None,
    project_profile: str | None = None,
    global_override: str | None = None,
    profile_registry: dict[str, AutomationProfile] | None = None,
) -> PrecedenceResolution:
    """Resolve the effective automation profile using the precedence chain.

    Implements the canonical plan > action > project > global precedence chain.
    The resolution is logged at ``DEBUG`` level so callers can trace
    which level provided the profile.

    Args:
        plan_profile: Profile name set at plan level (highest priority).
            ``None`` or empty string means no plan-level override.
        action_profile: Profile name set on the action template.
            ``None`` or empty string means no action-level override.
        project_profile: Profile name set at the project level.
            ``None`` or empty string means no project-level override.
        global_override: Explicit global profile name from config service.
            Falls back to ``CLEVERAGENTS_AUTOMATION_PROFILE`` env var,
            then ``"manual"``.
        profile_registry: Optional mapping of profile name → profile for
            custom profiles.  Built-in profiles are always available.
            Defaults to ``BUILTIN_PROFILES`` only.

    Returns:
        A :class:`PrecedenceResolution` describing the resolved profile
        and which level of the chain provided it.

    Raises:
        KeyError: If the resolved profile name is not found in the
            built-in profiles or the provided ``profile_registry``.

    Examples:
        >>> result = resolve_precedence_chain(plan_profile="ci")
        >>> result.source
        <PrecedenceSource.PLAN: 'plan'>
        >>> result.profile_name
        'ci'

        >>> result = resolve_precedence_chain(action_profile="auto")
        >>> result.source
        <PrecedenceSource.ACTION: 'action'>

        >>> result = resolve_precedence_chain(project_profile="trusted")
        >>> result.source
        <PrecedenceSource.PROJECT: 'project'>

        >>> result = resolve_precedence_chain()
        >>> result.source
        <PrecedenceSource.GLOBAL: 'global'>
        >>> result.profile_name
        'manual'
    """
    registry: dict[str, AutomationProfile] = dict(BUILTIN_PROFILES)
    if profile_registry:
        registry.update(profile_registry)

    # Normalise inputs — treat empty strings as absent
    norm_plan = plan_profile.strip() if isinstance(plan_profile, str) else None
    norm_plan = norm_plan if norm_plan else None

    norm_action = action_profile.strip() if isinstance(action_profile, str) else None
    norm_action = norm_action if norm_action else None

    norm_project = project_profile.strip() if isinstance(project_profile, str) else None
    norm_project = norm_project if norm_project else None

    effective_global = _resolve_global_profile(global_override)

    # Apply precedence chain: plan > action > project > global
    if norm_plan is not None:
        chosen_name = norm_plan
        source = PrecedenceSource.PLAN
    elif norm_action is not None:
        chosen_name = norm_action
        source = PrecedenceSource.ACTION
    elif norm_project is not None:
        chosen_name = norm_project
        source = PrecedenceSource.PROJECT
    else:
        chosen_name = effective_global
        source = PrecedenceSource.GLOBAL

    logger.debug(
        "Automation profile precedence chain resolved: "
        "name=%r source=%s plan=%r action=%r project=%r global=%r",
        chosen_name,
        source.value,
        norm_plan,
        norm_action,
        norm_project,
        effective_global,
    )

    profile = registry[chosen_name]

    return PrecedenceResolution(
        profile=profile,
        source=source,
        profile_name=chosen_name,
        plan_profile=norm_plan,
        action_profile=norm_action,
        project_profile=norm_project,
        global_profile=effective_global,
    )
