#!/usr/bin/env python3
"""
Environment variable configuration for BrowserOS build system

This module provides centralized access to all environment variables used by the build system.
It provides type-safe access, defaults, and clear documentation of what each variable is for.

The module automatically loads .env files from the project root on import.
"""

import os
from pathlib import Path
from typing import Optional

from dotenv import load_dotenv


def _load_dotenv_file():
    """Load .env file from project root"""
    from .paths import get_package_root

    browseros_root = get_package_root()
    project_root = browseros_root.parent.parent  # repo root

    # Try loading .env from multiple locations (most specific first)
    env_locations = [
        browseros_root / ".env",  # packages/browseros/.env
        project_root / ".env",  # repo root .env
    ]

    for env_path in env_locations:
        if env_path.exists():
            load_dotenv(env_path)
            return


# Load .env on module import
_load_dotenv_file()


class EnvConfig:
    """
    Centralized environment variable configuration

    This class provides clean, type-safe access to all environment variables
    used by the build system. It serves as the single source of truth for
    what environment variables are available and what they're used for.

    Usage:
        env = EnvConfig()
        if env.chromium_src:
            chromium_path = Path(env.chromium_src)
    """

    # === Build Configuration ===

    @property
    def chromium_src(self) -> Optional[str]:
        """Path to Chromium source directory"""
        return os.environ.get("CHROMIUM_SRC")

    @property
    def arch(self) -> Optional[str]:
        """Target architecture (x64, arm64, universal)"""
        return os.environ.get("ARCH")

    @property
    def pythonpath(self) -> Optional[str]:
        """Python path for build scripts"""
        return os.environ.get("PYTHONPATH")

    @property
    def depot_tools_win_toolchain(self) -> str:
        """Windows depot_tools toolchain setting (0 = use system toolchain)"""
        return os.environ.get("DEPOT_TOOLS_WIN_TOOLCHAIN", "0")

    # === macOS Code Signing ===

    @property
    def macos_certificate_name(self) -> Optional[str]:
        """macOS code signing certificate name"""
        return os.environ.get("MACOS_CERTIFICATE_NAME")

    @property
    def macos_notarization_apple_id(self) -> Optional[str]:
        """Apple ID for macOS notarization"""
        return os.environ.get("PROD_MACOS_NOTARIZATION_APPLE_ID")

    @property
    def macos_notarization_team_id(self) -> Optional[str]:
        """Team ID for macOS notarization"""
        return os.environ.get("PROD_MACOS_NOTARIZATION_TEAM_ID")

    @property
    def macos_notarization_password(self) -> Optional[str]:
        """App-specific password for macOS notarization"""
        return os.environ.get("PROD_MACOS_NOTARIZATION_PWD")

    @property
    def macos_keychain_password(self) -> Optional[str]:
        """macOS login keychain password (used to unlock keychain on build servers)"""
        return os.environ.get("MACOS_KEYCHAIN_PASSWORD")

    # === Windows Code Signing ===

    @property
    def code_sign_tool_path(self) -> Optional[str]:
        """Path to Windows code signing tool directory (legacy, use CODE_SIGN_TOOL_EXE instead)"""
        return os.environ.get("CODE_SIGN_TOOL_PATH")

    @property
    def code_sign_tool_exe(self) -> Optional[str]:
        """Path to CodeSignTool executable (CodeSignTool.sh on macOS/Linux, CodeSignTool.bat on Windows)"""
        return os.environ.get("CODE_SIGN_TOOL_EXE")

    @property
    def esigner_username(self) -> Optional[str]:
        """eSigner username for Windows code signing"""
        return os.environ.get("ESIGNER_USERNAME")

    @property
    def esigner_password(self) -> Optional[str]:
        """eSigner password for Windows code signing"""
        return os.environ.get("ESIGNER_PASSWORD")

    @property
    def esigner_totp_secret(self) -> Optional[str]:
        """eSigner TOTP secret for Windows code signing"""
        return os.environ.get("ESIGNER_TOTP_SECRET")

    @property
    def esigner_credential_id(self) -> Optional[str]:
        """eSigner credential ID for Windows code signing"""
        return os.environ.get("ESIGNER_CREDENTIAL_ID")

    # === Upload & Distribution (Cloudflare R2) ===

    @property
    def r2_account_id(self) -> Optional[str]:
        """Cloudflare account ID for R2"""
        return os.environ.get("R2_ACCOUNT_ID")

    @property
    def r2_access_key_id(self) -> Optional[str]:
        """R2 access key ID"""
        return os.environ.get("R2_ACCESS_KEY_ID")

    @property
    def r2_secret_access_key(self) -> Optional[str]:
        """R2 secret access key"""
        return os.environ.get("R2_SECRET_ACCESS_KEY")

    @property
    def r2_bucket(self) -> str:
        """R2 bucket name (default: browseros)"""
        return os.environ.get("R2_BUCKET", "browseros")

    @property
    def r2_cdn_base_url(self) -> str:
        """CDN base URL for R2 artifacts (default: http://cdn.browseros.com)"""
        return os.environ.get("R2_CDN_BASE_URL", "http://cdn.browseros.com")

    @property
    def r2_endpoint_url(self) -> Optional[str]:
        """R2 S3-compatible endpoint URL (computed from account ID)"""
        account_id = self.r2_account_id
        if account_id:
            return f"https://{account_id}.r2.cloudflarestorage.com"
        return None

    # === Sparkle Signing (macOS) ===

    @property
    def sparkle_private_key(self) -> Optional[str]:
        """Base64-encoded Sparkle Ed25519 private key for macOS auto-update signing"""
        return os.environ.get("SPARKLE_PRIVATE_KEY")

    @property
    def sparkle_sign_update_path(self) -> Optional[str]:
        """Path to Sparkle sign_update tool (overrides auto-detection)"""
        return os.environ.get("SPARKLE_SIGN_UPDATE_PATH")

    # === Notifications ===

    @property
    def slack_webhook_url(self) -> Optional[str]:
        """Slack webhook URL for build notifications"""
        return os.environ.get("SLACK_WEBHOOK_URL")

    # === Helper Methods ===

    def get_macos_signing_config(self) -> dict:
        """
        Get all macOS signing configuration as a dict

        Returns:
            dict with keys: certificate_name, apple_id, team_id, notarization_pwd
        """
        return {
            "certificate_name": self.macos_certificate_name or "",
            "apple_id": self.macos_notarization_apple_id or "",
            "team_id": self.macos_notarization_team_id or "",
            "notarization_pwd": self.macos_notarization_password or "",
        }

    def get_windows_signing_config(self) -> dict:
        """
        Get all Windows signing configuration as a dict

        Returns:
            dict with keys: code_sign_tool_path, username, password, totp_secret, credential_id
        """
        return {
            "code_sign_tool_path": self.code_sign_tool_path or "",
            "username": self.esigner_username or "",
            "password": self.esigner_password or "",
            "totp_secret": self.esigner_totp_secret or "",
            "credential_id": self.esigner_credential_id or "",
        }

    def validate_required(self, *var_names: str) -> None:
        """
        Validate that required environment variables are set

        Args:
            *var_names: Variable names to check (e.g., "chromium_src", "gcs_bucket")

        Raises:
            ValueError: If any required variable is not set

        Example:
            env = EnvConfig()
            env.validate_required("chromium_src", "macos_certificate_name")
        """
        missing = []
        for var_name in var_names:
            # Convert property name to env var name (e.g., chromium_src -> CHROMIUM_SRC)
            env_var = var_name.upper()
            if not os.environ.get(env_var):
                missing.append(env_var)

        if missing:
            raise ValueError(
                f"Missing required environment variables: {', '.join(missing)}"
            )

    def get_r2_config(self) -> dict:
        """
        Get all R2 configuration as a dict

        Returns:
            dict with keys: account_id, access_key_id, secret_access_key, bucket, cdn_base_url, endpoint_url
        """
        return {
            "account_id": self.r2_account_id or "",
            "access_key_id": self.r2_access_key_id or "",
            "secret_access_key": self.r2_secret_access_key or "",
            "bucket": self.r2_bucket,
            "cdn_base_url": self.r2_cdn_base_url,
            "endpoint_url": self.r2_endpoint_url or "",
        }

    def has_r2_config(self) -> bool:
        """Check if R2 upload configuration is available"""
        return bool(
            self.r2_account_id and self.r2_access_key_id and self.r2_secret_access_key
        )

    def has_sparkle_key(self) -> bool:
        """Check if Sparkle private key is available"""
        return bool(self.sparkle_private_key)
