"""Bank ID derivation and mission management for Codex.

Codex context dimensions:
  - agent   → configured name or "codex" (HINDSIGHT_AGENT_NAME)
  - project → derived from cwd (working directory basename)
  - session → session_id from hook input
  - user    → from env var HINDSIGHT_USER_ID

The channel dimension is omitted — Codex is a CLI tool without multi-channel
routing like Telegram/Discord agents.
"""

import os
import sys
import urllib.parse

from .state import read_state, write_state

DEFAULT_BANK_NAME = "codex"

# Valid granularity fields for Codex
VALID_FIELDS = {"agent", "project", "session", "user"}


def derive_bank_id(hook_input: dict, config: dict) -> str:
    """Derive a bank ID from hook context and config.

    When dynamicBankId is false, returns the static bank.
    When true, composes from granularity fields joined by '::'.
    """
    prefix = config.get("bankIdPrefix", "")

    if not config.get("dynamicBankId", False):
        base = config.get("bankId") or DEFAULT_BANK_NAME
        return f"{prefix}-{base}" if prefix else base

    # Dynamic mode — compose from granularity fields
    fields = config.get("dynamicBankGranularity")
    if not fields or not isinstance(fields, list):
        fields = ["agent", "project"]

    for f in fields:
        if f not in VALID_FIELDS:
            print(
                f'[Hindsight] Unknown dynamicBankGranularity field "{f}" — '
                f"valid for Codex: {', '.join(sorted(VALID_FIELDS))}",
                file=sys.stderr,
            )

    cwd = hook_input.get("cwd", "")
    session_id = hook_input.get("session_id", "")
    agent_name = config.get("agentName", "codex")
    user_id = os.environ.get("HINDSIGHT_USER_ID", "")

    field_map = {
        "agent": agent_name,
        "project": os.path.basename(cwd) if cwd else "unknown",
        "session": session_id or "unknown",
        "user": user_id or "anonymous",
    }

    segments = [urllib.parse.quote(field_map.get(f, "unknown"), safe="") for f in fields]
    base_bank_id = "::".join(segments)

    return f"{prefix}-{base_bank_id}" if prefix else base_bank_id


def ensure_bank_mission(client, bank_id: str, config: dict, debug_fn=None):
    """Set bank mission on first use, skip if already set."""
    mission = config.get("bankMission", "")
    if not mission or not mission.strip():
        return

    missions_set = read_state("bank_missions.json", {})
    if bank_id in missions_set:
        return

    try:
        retain_mission = config.get("retainMission")
        client.set_bank_mission(bank_id, mission, retain_mission=retain_mission, timeout=10)
        missions_set[bank_id] = True
        if len(missions_set) > 10000:
            keys = sorted(missions_set.keys())
            for k in keys[: len(keys) // 2]:
                del missions_set[k]
        write_state("bank_missions.json", missions_set)
        if debug_fn:
            debug_fn(f"Set mission for bank: {bank_id}")
    except Exception as e:
        if debug_fn:
            debug_fn(f"Could not set bank mission for {bank_id}: {e}")
