# retoor <retoor@molodetz.nl>

from __future__ import annotations

import os
import uuid
from dataclasses import dataclass

from devplacepy.config import (
    INTERNAL_GATEWAY_URL,
    INTERNAL_MODEL,
    DEVII_TASKS_DB,
    DEVII_LESSONS_DB,
    PORT,
)


DEFAULT_AI_URL = INTERNAL_GATEWAY_URL
DEFAULT_AI_MODEL = INTERNAL_MODEL
DEFAULT_BASE_URL = f"http://127.0.0.1:{PORT}"
CONTEXT_WINDOW_TOKENS = 1_048_576
MAX_OUTPUT_TOKENS = 384_000
SYSTEM_RESERVE_TOKENS = 64_000
CHARS_PER_TOKEN = 3
CONTEXT_INPUT_BUDGET_TOKENS = (
    CONTEXT_WINDOW_TOKENS - MAX_OUTPUT_TOKENS - SYSTEM_RESERVE_TOKENS
)

MIN_TIMEOUT_SECONDS = 300.0
DEFAULT_TIMEOUT_SECONDS = 300.0
DEFAULT_MAX_RESPONSE_CHARS = 200_000
DEFAULT_MAX_TOOL_ITERATIONS = 40
DEFAULT_DELEGATE_MAX_ITERATIONS = 25
DEFAULT_CONTEXT_COMPACT_THRESHOLD = CONTEXT_INPUT_BUDGET_TOKENS * CHARS_PER_TOKEN
DEFAULT_CONTEXT_KEEP_TAIL = 12
DEFAULT_RECALL_TOP_K = 3
DEFAULT_FETCH_MAX_CHARS = 200_000
DEFAULT_FETCH_TIMEOUT_SECONDS = 300.0
DEFAULT_FETCH_MAX_BYTES = 8_000_000
DEFAULT_RSEARCH_URL = "https://rsearch.app.molodetz.nl"
DEFAULT_RSEARCH_TIMEOUT_SECONDS = 300.0
DEFAULT_EMAIL_TIMEOUT_SECONDS = 30.0


@dataclass(frozen=True)
class Settings:
    ai_url: str
    ai_key: str
    ai_model: str
    base_url: str
    timeout_seconds: float
    max_response_chars: int
    max_tool_iterations: int
    log_level: str
    log_path: str
    tasks_db_path: str
    scheduler_tick_seconds: float
    lessons_db_path: str
    delegate_max_iterations: int
    context_compact_threshold: int
    context_keep_tail: int
    recall_top_k: int
    plan_required: bool
    verify_required: bool
    platform_api_key: str
    login_email: str
    login_password: str
    fetch_max_chars: int
    fetch_timeout_seconds: float
    fetch_max_bytes: int
    fetch_allow_private: bool
    allow_eval: bool
    browser_control: bool
    rsearch_enabled: bool
    rsearch_url: str
    rsearch_timeout_seconds: float
    email_enabled: bool
    email_timeout_seconds: float
    daily_limit_usd: float


def _default_ai_key() -> str:
    env_key = os.environ.get("DEVII_AI_KEY", "")
    if env_key:
        return env_key
    try:
        from devplacepy.database import internal_gateway_key

        key = internal_gateway_key()
        if key:
            return key
    except Exception:  # noqa: BLE001 - no local DB / remote-only: fall back to a random key
        pass
    return str(uuid.uuid4())


def load_settings() -> Settings:
    return Settings(
        ai_url=os.environ.get("DEVII_AI_URL", DEFAULT_AI_URL),
        ai_key=_default_ai_key(),
        ai_model=os.environ.get("DEVII_AI_MODEL", DEFAULT_AI_MODEL),
        base_url=os.environ.get("DEVII_BASE_URL", DEFAULT_BASE_URL).rstrip("/"),
        timeout_seconds=float(os.environ.get("DEVII_TIMEOUT", DEFAULT_TIMEOUT_SECONDS)),
        max_response_chars=int(
            os.environ.get("DEVII_MAX_RESPONSE", DEFAULT_MAX_RESPONSE_CHARS)
        ),
        max_tool_iterations=int(
            os.environ.get("DEVII_MAX_TOOL_ITERATIONS", DEFAULT_MAX_TOOL_ITERATIONS)
        ),
        log_level=os.environ.get("DEVII_LOG_LEVEL", "WARNING").upper(),
        log_path=os.environ.get("DEVII_LOG_PATH", "devii.log"),
        tasks_db_path=os.environ.get("DEVII_TASKS_DB", str(DEVII_TASKS_DB)),
        scheduler_tick_seconds=float(os.environ.get("DEVII_SCHEDULER_TICK", "1.0")),
        lessons_db_path=os.environ.get("DEVII_LESSONS_DB", str(DEVII_LESSONS_DB)),
        delegate_max_iterations=int(
            os.environ.get(
                "DEVII_DELEGATE_MAX_ITERATIONS", DEFAULT_DELEGATE_MAX_ITERATIONS
            )
        ),
        context_compact_threshold=int(
            os.environ.get(
                "DEVII_CONTEXT_COMPACT_THRESHOLD", DEFAULT_CONTEXT_COMPACT_THRESHOLD
            )
        ),
        context_keep_tail=int(
            os.environ.get("DEVII_CONTEXT_KEEP_TAIL", DEFAULT_CONTEXT_KEEP_TAIL)
        ),
        recall_top_k=int(os.environ.get("DEVII_RECALL_TOP_K", DEFAULT_RECALL_TOP_K)),
        plan_required=os.environ.get("DEVII_PLAN_REQUIRED", "1").lower()
        not in ("0", "false", "no"),
        verify_required=os.environ.get("DEVII_VERIFY_REQUIRED", "1").lower()
        not in ("0", "false", "no"),
        platform_api_key=os.environ.get("DEVII_PLATFORM_API_KEY", ""),
        login_email=os.environ.get("DEVII_LOGIN_EMAIL", ""),
        login_password=os.environ.get("DEVII_LOGIN_PASSWORD", ""),
        fetch_max_chars=int(
            os.environ.get("DEVII_FETCH_MAX_CHARS", DEFAULT_FETCH_MAX_CHARS)
        ),
        fetch_timeout_seconds=float(
            os.environ.get("DEVII_FETCH_TIMEOUT", DEFAULT_FETCH_TIMEOUT_SECONDS)
        ),
        fetch_max_bytes=int(
            os.environ.get("DEVII_FETCH_MAX_BYTES", DEFAULT_FETCH_MAX_BYTES)
        ),
        fetch_allow_private=os.environ.get("DEVII_FETCH_ALLOW_PRIVATE", "0").lower()
        in ("1", "true", "yes", "on"),
        allow_eval=os.environ.get("DEVII_ALLOW_EVAL", "1").lower()
        in ("1", "true", "yes", "on"),
        browser_control=os.environ.get("DEVII_BROWSER_CONTROL", "1").lower()
        in ("1", "true", "yes", "on"),
        rsearch_enabled=os.environ.get("DEVII_RSEARCH_ENABLED", "1").lower()
        in ("1", "true", "yes", "on"),
        rsearch_url=os.environ.get("DEVII_RSEARCH_URL", DEFAULT_RSEARCH_URL).rstrip(
            "/"
        ),
        rsearch_timeout_seconds=float(
            os.environ.get("DEVII_RSEARCH_TIMEOUT", DEFAULT_RSEARCH_TIMEOUT_SECONDS)
        ),
        email_enabled=os.environ.get("DEVII_EMAIL_ENABLED", "1").lower()
        in ("1", "true", "yes", "on"),
        email_timeout_seconds=float(
            os.environ.get("DEVII_EMAIL_TIMEOUT", DEFAULT_EMAIL_TIMEOUT_SECONDS)
        ),
        daily_limit_usd=0.0,
    )


FIELD_AI_URL = "devii_ai_url"
FIELD_AI_MODEL = "devii_ai_model"
FIELD_AI_KEY = "devii_ai_key"
FIELD_PLAN_REQUIRED = "devii_plan_required"
FIELD_VERIFY_REQUIRED = "devii_verify_required"
FIELD_MAX_ITERATIONS = "devii_max_iterations"
FIELD_USER_DAILY_USD = "devii_user_daily_usd"
FIELD_GUEST_DAILY_USD = "devii_guest_daily_usd"
FIELD_ADMIN_DAILY_USD = "devii_admin_daily_usd"
FIELD_GUESTS_ENABLED = "devii_guests_enabled"
FIELD_PRICE_CACHE_HIT = "devii_price_cache_hit"
FIELD_PRICE_CACHE_MISS = "devii_price_cache_miss"
FIELD_PRICE_OUTPUT = "devii_price_output"
FIELD_ALLOW_EVAL = "devii_allow_eval"
FIELD_INTERACTIONS_DEFAULT = "devii_interactions_default"
FIELD_BROWSER_CONTROL = "devii_browser_control"
FIELD_TIMEOUT = "devii_timeout"
FIELD_FETCH_TIMEOUT = "devii_fetch_timeout"
FIELD_RSEARCH_ENABLED = "devii_rsearch_enabled"
FIELD_RSEARCH_URL = "devii_rsearch_url"
FIELD_RSEARCH_TIMEOUT = "devii_rsearch_timeout"
FIELD_EMAIL_ENABLED = "devii_email_enabled"
FIELD_EMAIL_TIMEOUT = "devii_email_timeout"
FIELD_TASK_MAX_CONCURRENT = "devii_task_max_concurrent"
FIELD_TASK_MAX_PER_OWNER = "devii_task_max_per_owner"
FIELD_TASK_DAILY_USD = "devii_task_daily_usd"
FIELD_TASK_MAX_FAILURES = "devii_task_max_failures"
FIELD_TASK_IDLE_DAYS = "devii_task_owner_idle_days"

DEFAULT_TASK_MAX_CONCURRENT = 4
DEFAULT_TASK_DAILY_USD = 0.5
DEFAULT_TASK_MAX_FAILURES = 3
DEFAULT_TASK_IDLE_DAYS = 30

LESSONS_DB_PATH = os.environ.get("DEVII_LESSONS_DB", str(DEVII_LESSONS_DB))


def effective_daily_limit(
    config: dict, owner_kind: str, is_admin: bool = False
) -> float:
    if is_admin:
        return float(config.get(FIELD_ADMIN_DAILY_USD, 0.0) or 0.0)
    if owner_kind == "guest":
        return float(config.get(FIELD_GUEST_DAILY_USD, 0.05) or 0.0)
    return float(config.get(FIELD_USER_DAILY_USD, 1.0) or 0.0)


def build_settings(
    config: dict,
    base_url: str,
    api_key: str,
    owner_kind: str = "guest",
    is_admin: bool = False,
) -> Settings:
    configured_key = config[FIELD_AI_KEY] or str(uuid.uuid4())
    ai_key = api_key if (owner_kind == "user" and api_key) else configured_key
    return Settings(
        ai_url=config[FIELD_AI_URL] or DEFAULT_AI_URL,
        ai_key=ai_key,
        ai_model=config[FIELD_AI_MODEL] or DEFAULT_AI_MODEL,
        base_url=(base_url or DEFAULT_BASE_URL).rstrip("/"),
        timeout_seconds=float(config.get(FIELD_TIMEOUT) or DEFAULT_TIMEOUT_SECONDS),
        max_response_chars=DEFAULT_MAX_RESPONSE_CHARS,
        max_tool_iterations=int(config[FIELD_MAX_ITERATIONS]),
        log_level="INFO",
        log_path="devii.log",
        tasks_db_path="",
        scheduler_tick_seconds=1.0,
        lessons_db_path=LESSONS_DB_PATH,
        delegate_max_iterations=DEFAULT_DELEGATE_MAX_ITERATIONS,
        context_compact_threshold=DEFAULT_CONTEXT_COMPACT_THRESHOLD,
        context_keep_tail=DEFAULT_CONTEXT_KEEP_TAIL,
        recall_top_k=DEFAULT_RECALL_TOP_K,
        plan_required=bool(config[FIELD_PLAN_REQUIRED]),
        verify_required=bool(config[FIELD_VERIFY_REQUIRED]),
        platform_api_key=api_key,
        login_email="",
        login_password="",
        fetch_max_chars=DEFAULT_FETCH_MAX_CHARS,
        fetch_timeout_seconds=float(
            config.get(FIELD_FETCH_TIMEOUT) or DEFAULT_FETCH_TIMEOUT_SECONDS
        ),
        fetch_max_bytes=DEFAULT_FETCH_MAX_BYTES,
        fetch_allow_private=False,
        allow_eval=bool(config.get(FIELD_ALLOW_EVAL, True)),
        browser_control=bool(config.get(FIELD_BROWSER_CONTROL, True)),
        rsearch_enabled=bool(config.get(FIELD_RSEARCH_ENABLED, True)),
        rsearch_url=(config.get(FIELD_RSEARCH_URL) or DEFAULT_RSEARCH_URL).rstrip("/"),
        rsearch_timeout_seconds=float(
            config.get(FIELD_RSEARCH_TIMEOUT) or DEFAULT_RSEARCH_TIMEOUT_SECONDS
        ),
        email_enabled=bool(config.get(FIELD_EMAIL_ENABLED, True)),
        email_timeout_seconds=float(
            config.get(FIELD_EMAIL_TIMEOUT) or DEFAULT_EMAIL_TIMEOUT_SECONDS
        ),
        daily_limit_usd=effective_daily_limit(config, owner_kind, is_admin),
    )
