"""Shared profile/env/CLI resolution helpers for command modules."""

from __future__ import annotations

import os
from dataclasses import dataclass
from typing import Any

import typer

from worai.core.profile_loader import load_profile, resolve_profile_name


def load_profile_settings(ctx: typer.Context | None) -> tuple[dict[str, Any], str]:
    safe_ctx = ctx if hasattr(ctx, "obj") else None
    try:
        profile, profile_name, _ = load_profile(safe_ctx)
    except ValueError:
        return {}, resolve_profile_name(safe_ctx)
    settings = getattr(profile, "settings", {}) or {}
    return settings, profile_name


def resolve_value(
    value: Any,
    profile_settings: dict[str, Any],
    *,
    paths: list[str] | None = None,
    env_keys: list[str] | None = None,
) -> Any:
    if value is not None and value != "":
        return value
    for env_key in env_keys or []:
        if env_key in os.environ:
            return os.environ[env_key]
    for path in paths or []:
        underscore_key = path.replace(".", "_")
        if underscore_key in profile_settings:
            return profile_settings[underscore_key]
        if path in profile_settings:
            return profile_settings[path]
        # Traverse nested dicts for dotted paths (e.g. "gsheets.credentials"
        # maps to {"gsheets": {"credentials": ...}}).
        parts = path.split(".")
        if len(parts) > 1:
            node: Any = profile_settings
            for part in parts:
                if not isinstance(node, dict) or part not in node:
                    node = None
                    break
                node = node[part]
            if node is not None:
                return node
    return None


def resolve_int_value(
    value: int | None,
    profile_settings: dict[str, Any],
    *,
    paths: list[str] | None = None,
    env_keys: list[str] | None = None,
    minimum: int | None = None,
    label: str | None = None,
) -> int | None:
    if value is not None:
        parsed = int(value)
    else:
        raw = resolve_value(None, profile_settings, paths=paths, env_keys=env_keys)
        if raw is None:
            return None
        try:
            parsed = int(raw)
        except (TypeError, ValueError) as exc:
            target = label or (paths[0] if paths else "value")
            raise ValueError(f"Invalid integer value for {target}: {raw}") from exc
    if minimum is not None and parsed < minimum:
        target = label or (paths[0] if paths else "value")
        raise ValueError(f"Invalid value for {target}: {parsed}. Must be >= {minimum}.")
    return parsed


@dataclass(frozen=True)
class IngestRuntimeSettings:
    timeout_ms: int | None = None
    retry_attempts: int | None = None
    retry_backoff_ms: int | None = None
    playwright_wait_until: str | None = None


def resolve_ingest_runtime_settings(
    profile_settings: dict[str, Any],
    *,
    timeout_ms: int | None = None,
    retry_attempts: int | None = None,
    retry_backoff_ms: int | None = None,
    playwright_wait_until: str | None = None,
) -> IngestRuntimeSettings:
    return IngestRuntimeSettings(
        timeout_ms=resolve_int_value(
            timeout_ms,
            profile_settings,
            paths=["ingest.timeout_ms"],
            env_keys=["INGEST_TIMEOUT_MS"],
            minimum=1,
            label="ingest.timeout_ms",
        ),
        retry_attempts=resolve_int_value(
            retry_attempts,
            profile_settings,
            paths=["ingest.retry_attempts"],
            env_keys=["INGEST_RETRY_ATTEMPTS"],
            minimum=1,
            label="ingest.retry_attempts",
        ),
        retry_backoff_ms=resolve_int_value(
            retry_backoff_ms,
            profile_settings,
            paths=["ingest.retry_backoff_ms"],
            env_keys=["INGEST_RETRY_BACKOFF_MS"],
            minimum=0,
            label="ingest.retry_backoff_ms",
        ),
        playwright_wait_until=resolve_value(
            playwright_wait_until,
            profile_settings,
            paths=["ingest.playwright_wait_until"],
            env_keys=["PLAYWRIGHT_WAIT_UNTIL"],
        ),
    )


def resolve_token_path(
    token_value: str | None,
    profile_settings: dict[str, Any],
) -> str:
    return str(
        resolve_value(
            token_value,
            profile_settings,
            paths=["oauth.token", "gsc.token", "ga.token"],
            env_keys=["OAUTH_TOKEN", "GSC_TOKEN", "GA_TOKEN"],
        )
        or "oauth_token.json"
    )


def resolve_oauth_client_secrets(
    client_secrets_value: str | None,
    profile_settings: dict[str, Any],
) -> str | None:
    return resolve_value(
        client_secrets_value,
        profile_settings,
        paths=["oauth.client_secrets"],
        env_keys=["GSC_CLIENT_SECRETS"],
    )


def resolve_gsc_site_id(
    site_value: str | None,
    profile_settings: dict[str, Any],
) -> str | None:
    return resolve_value(
        site_value,
        profile_settings,
        paths=["gsc_site_id", "gsc.id"],
        env_keys=["GSC_ID"],
    )


def resolve_ga_property_id(
    ga_value: str | None,
    profile_settings: dict[str, Any],
) -> str | None:
    return resolve_value(
        ga_value,
        profile_settings,
        paths=["ga_property_id", "ga.id"],
        env_keys=["GA_ID"],
    )


def resolve_gsheets_credentials(
    value: str | None,
    profile_settings: dict[str, Any],
) -> str | None:
    return resolve_value(
        value,
        profile_settings,
        paths=["gsheets.credentials"],
        env_keys=["GSHEETS_CREDENTIALS"],
    )


def resolve_gsheets_spreadsheet_id(
    value: str | None,
    profile_settings: dict[str, Any],
) -> str | None:
    return resolve_value(
        value,
        profile_settings,
        paths=["gsheets.spreadsheet_id"],
        env_keys=["GSHEETS_SPREADSHEET_ID"],
    )


def resolve_gsheets_sheet_name(
    value: str | None,
    profile_settings: dict[str, Any],
) -> str | None:
    return resolve_value(
        value,
        profile_settings,
        paths=["gsheets.sheet_name"],
        env_keys=["GSHEETS_SHEET_NAME"],
    )
