from __future__ import annotations

import os
from dataclasses import dataclass
from urllib.parse import urlencode
from pathlib import Path
from dotenv import load_dotenv

from . import __version__


@dataclass(frozen=True)
class AgentConfig:
    erp_base_url: str
    node_code: str
    node_secret: str
    storage_root: Path
    tenant_id: str | None = None
    branch_id: str | None = None
    poll_interval_seconds: int = 30
    download_request_interval_seconds: int = 30
    heartbeat_interval_seconds: int = 60
    request_timeout_seconds: int = 60
    max_retries: int = 3
    tunnel_enabled: bool = True
    tunnel_reconnect_seconds: int = 10
    auto_update: bool = True
    update_check_interval_seconds: int = 300

    @property
    def headers(self) -> dict[str, str]:
        return {
            "X-Node-Code": self.node_code,
            "X-Node-Secret": self.node_secret,
            "User-Agent": f"ERPLocalAgent/{__version__}",
        }

    @property
    def tunnel_url(self) -> str:
        base = self.erp_base_url.rstrip("/")
        if base.startswith("https://"):
            ws_base = "wss://" + base[len("https://"):]
        elif base.startswith("http://"):
            ws_base = "ws://" + base[len("http://"):]
        else:
            ws_base = base
        query = urlencode({"node_code": self.node_code, "node_secret": self.node_secret})
        return f"{ws_base}/documents/storage-agent/tunnel?{query}"


def _get_bool(name: str, default: bool) -> bool:
    raw = os.getenv(name)
    if raw is None or str(raw).strip() == "":
        return default
    return str(raw).strip().lower() in {"1", "true", "yes", "y", "on"}


def _get_int(name: str, default: int) -> int:
    raw = os.getenv(name)
    if raw is None or str(raw).strip() == "":
        return default
    try:
        return int(raw)
    except ValueError as exc:
        raise RuntimeError(f"Invalid integer for {name}: {raw!r}") from exc


def load_config(env_file: str | None = None) -> AgentConfig:
    if env_file:
        load_dotenv(env_file)
    else:
        load_dotenv()

    erp_base_url = os.getenv("ERP_BASE_URL", "").rstrip("/")
    node_code = os.getenv("NODE_CODE", "").strip()
    node_secret = os.getenv("NODE_SECRET", "").strip()
    storage_root_raw = os.getenv("STORAGE_ROOT", "").strip()
    tenant_id = os.getenv("TENANT_ID", os.getenv("AUDIT_FIRM_ID", "")).strip() or None
    branch_id = os.getenv("BRANCH_ID", "").strip() or None

    missing = []
    if not erp_base_url:
        missing.append("ERP_BASE_URL")
    if not node_code:
        missing.append("NODE_CODE")
    if not node_secret:
        missing.append("NODE_SECRET")
    if not storage_root_raw:
        missing.append("STORAGE_ROOT")
    if missing:
        raise RuntimeError("Missing required configuration: " + ", ".join(missing))

    storage_root = Path(storage_root_raw).expanduser().resolve()
    storage_root.mkdir(parents=True, exist_ok=True)

    return AgentConfig(
        erp_base_url=erp_base_url,
        node_code=node_code,
        node_secret=node_secret,
        storage_root=storage_root,
        tenant_id=tenant_id,
        branch_id=branch_id,
        poll_interval_seconds=_get_int("POLL_INTERVAL_SECONDS", 30),
        download_request_interval_seconds=_get_int("DOWNLOAD_REQUEST_INTERVAL_SECONDS", 30),
        heartbeat_interval_seconds=_get_int("HEARTBEAT_INTERVAL_SECONDS", 60),
        request_timeout_seconds=_get_int("REQUEST_TIMEOUT_SECONDS", 60),
        max_retries=_get_int("MAX_RETRIES", 3),
        tunnel_enabled=_get_bool("TUNNEL_ENABLED", True),
        tunnel_reconnect_seconds=_get_int("TUNNEL_RECONNECT_SECONDS", 10),
        auto_update=_get_bool("AUTO_UPDATE", True),
        update_check_interval_seconds=max(60, _get_int("UPDATE_CHECK_INTERVAL_SECONDS", 300)),
    )
