from pathlib import Path

from pydantic import AliasChoices, Field
from pydantic_settings import BaseSettings, SettingsConfigDict


def codexmobile_env(name: str) -> AliasChoices:
    """Prefer the CodexMobile env name while keeping old CodexBot installs working."""
    return AliasChoices(name.replace("CODEXBOT_", "CODEXMOBILE_"), name)


class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file=".env",
        env_file_encoding="utf-8",
        extra="ignore",
    )

    telegram_bot_token: str = Field(alias="TELEGRAM_BOT_TOKEN")
    telegram_allowed_user_ids: str = Field(alias="TELEGRAM_ALLOWED_USER_IDS")
    openai_api_key: str | None = Field(default=None, alias="OPENAI_API_KEY")
    codexbot_agent_model: str = Field(default="gpt-5", validation_alias=codexmobile_env("CODEXBOT_AGENT_MODEL"))
    codexbot_intent_model: str = Field(default="gpt-4.1-mini", validation_alias=codexmobile_env("CODEXBOT_INTENT_MODEL"))
    codexbot_transcribe_model: str = Field(
        default="gpt-4o-mini-transcribe",
        validation_alias=codexmobile_env("CODEXBOT_TRANSCRIBE_MODEL"),
    )
    codexbot_transcribe_language: str = Field(default="zh", validation_alias=codexmobile_env("CODEXBOT_TRANSCRIBE_LANGUAGE"))
    codexbot_workdir: Path = Field(default=Path("/root/codexmobile-workspace"), validation_alias=codexmobile_env("CODEXBOT_WORKDIR"))
    codexbot_state_path: Path = Field(default=Path("./data/state.json"), validation_alias=codexmobile_env("CODEXBOT_STATE_PATH"))
    codexbot_log_level: str = Field(default="INFO", validation_alias=codexmobile_env("CODEXBOT_LOG_LEVEL"))
    codexbot_worker_poll_seconds: float = Field(default=2.0, validation_alias=codexmobile_env("CODEXBOT_WORKER_POLL_SECONDS"))
    codexbot_max_output_chars: int = Field(default=4000, validation_alias=codexmobile_env("CODEXBOT_MAX_OUTPUT_CHARS"))
    codexbot_mac_service_host: str = Field(default="127.0.0.1", validation_alias=codexmobile_env("CODEXBOT_MAC_SERVICE_HOST"))
    codexbot_mac_service_port: int = Field(default=8765, validation_alias=codexmobile_env("CODEXBOT_MAC_SERVICE_PORT"))
    codexbot_mac_service_token: str | None = Field(default=None, validation_alias=codexmobile_env("CODEXBOT_MAC_SERVICE_TOKEN"))
    codexbot_mac_service_url: str | None = Field(default=None, validation_alias=codexmobile_env("CODEXBOT_MAC_SERVICE_URL"))
    codexbot_mac_service_timeout_seconds: float = Field(default=240.0, validation_alias=codexmobile_env("CODEXBOT_MAC_SERVICE_TIMEOUT_SECONDS"))
    codexbot_app_api_host: str = Field(default="127.0.0.1", validation_alias=codexmobile_env("CODEXBOT_APP_API_HOST"))
    codexbot_app_api_port: int = Field(default=8787, validation_alias=codexmobile_env("CODEXBOT_APP_API_PORT"))
    codexbot_app_api_token: str | None = Field(default=None, validation_alias=codexmobile_env("CODEXBOT_APP_API_TOKEN"))
    codexbot_relay_db_path: Path | None = Field(default=None, validation_alias=codexmobile_env("CODEXBOT_RELAY_DB_PATH"))
    codexbot_relay_owner_email: str | None = Field(default=None, validation_alias=codexmobile_env("CODEXBOT_RELAY_OWNER_EMAIL"))
    codexbot_desktop_bridge_host: str = Field(default="127.0.0.1", validation_alias=codexmobile_env("CODEXBOT_DESKTOP_BRIDGE_HOST"))
    codexbot_desktop_bridge_port: int = Field(default=8766, validation_alias=codexmobile_env("CODEXBOT_DESKTOP_BRIDGE_PORT"))
    codexbot_desktop_bridge_token: str | None = Field(default=None, validation_alias=codexmobile_env("CODEXBOT_DESKTOP_BRIDGE_TOKEN"))
    codexbot_desktop_bridge_state_path: Path = Field(
        default=Path("./data/desktop-bridge.json"),
        validation_alias=codexmobile_env("CODEXBOT_DESKTOP_BRIDGE_STATE_PATH"),
    )
    codexbot_desktop_bridge_inbox_path: Path = Field(
        default=Path("./data/desktop-bridge-inbox.md"),
        validation_alias=codexmobile_env("CODEXBOT_DESKTOP_BRIDGE_INBOX_PATH"),
    )
    codexbot_live_app_server_url: str = Field(default="ws://127.0.0.1:8791", validation_alias=codexmobile_env("CODEXBOT_LIVE_APP_SERVER_URL"))
    codexbot_live_codex_bin: Path = Field(
        default=Path("/Applications/Codex.app/Contents/Resources/codex"),
        validation_alias=codexmobile_env("CODEXBOT_LIVE_CODEX_BIN"),
    )
    codexbot_live_probe_script: Path = Field(
        default=Path("./scripts/codex_app_server_probe.mjs"),
        validation_alias=codexmobile_env("CODEXBOT_LIVE_PROBE_SCRIPT"),
    )
    codexbot_live_node_bin: str = Field(default="node", validation_alias=codexmobile_env("CODEXBOT_LIVE_NODE_BIN"))
    codexbot_live_thread_cwd: Path = Field(default=Path.cwd(), validation_alias=codexmobile_env("CODEXBOT_LIVE_THREAD_CWD"))
    codexbot_project_root: Path = Field(default=Path.home(), validation_alias=codexmobile_env("CODEXBOT_PROJECT_ROOT"))
    codexbot_live_thread_name: str | None = Field(default=None, validation_alias=codexmobile_env("CODEXBOT_LIVE_THREAD_NAME"))
    codexbot_live_spawn_app_server: bool = Field(default=True, validation_alias=codexmobile_env("CODEXBOT_LIVE_SPAWN_APP_SERVER"))
    codexbot_live_timeout_seconds: float = Field(default=120.0, validation_alias=codexmobile_env("CODEXBOT_LIVE_TIMEOUT_SECONDS"))
    codexbot_live_snapshot_app_server_timeout_seconds: float = Field(
        default=2.0,
        validation_alias=codexmobile_env("CODEXBOT_LIVE_SNAPSHOT_APP_SERVER_TIMEOUT_SECONDS"),
    )
    codexbot_auto_refresh_codex_desktop: bool = Field(
        default=False,
        validation_alias=codexmobile_env("CODEXBOT_AUTO_REFRESH_CODEX_DESKTOP"),
    )
    codexbot_live_selection_path: Path = Field(
        default=Path("./data/live-thread-selection.json"),
        validation_alias=codexmobile_env("CODEXBOT_LIVE_SELECTION_PATH"),
    )
    codexbot_live_projects_path: Path = Field(
        default=Path("./data/live-projects.json"),
        validation_alias=codexmobile_env("CODEXBOT_LIVE_PROJECTS_PATH"),
    )
    codexbot_desktop_send_queue_path: Path = Field(
        default=Path("./data/desktop-send-queue.json"),
        validation_alias=codexmobile_env("CODEXBOT_DESKTOP_SEND_QUEUE_PATH"),
    )
    codexbot_allowed_commands: str = Field(
        default="pwd,ls,find,rg,cat,sed,tail,head,python3,pytest",
        validation_alias=codexmobile_env("CODEXBOT_ALLOWED_COMMANDS"),
    )

    def model_post_init(self, __context) -> None:
        repo_root = Path(__file__).resolve().parents[2]
        path_fields = [
            "codexbot_workdir",
            "codexbot_state_path",
            "codexbot_desktop_bridge_state_path",
            "codexbot_desktop_bridge_inbox_path",
            "codexbot_live_codex_bin",
            "codexbot_live_probe_script",
            "codexbot_live_thread_cwd",
            "codexbot_project_root",
            "codexbot_live_selection_path",
            "codexbot_live_projects_path",
            "codexbot_desktop_send_queue_path",
            "codexbot_relay_db_path",
        ]
        for field_name in path_fields:
            value = getattr(self, field_name)
            if isinstance(value, Path) and not value.is_absolute():
                setattr(self, field_name, (repo_root / value).resolve())

    @property
    def allowed_user_ids(self) -> set[int]:
        parts = [part.strip() for part in self.telegram_allowed_user_ids.split(",") if part.strip()]
        return {int(part) for part in parts}

    @property
    def allowed_commands(self) -> set[str]:
        return {part.strip() for part in self.codexbot_allowed_commands.split(",") if part.strip()}
