import os
import stat
import json
import sys
import tempfile
from pathlib import Path
from dataclasses import dataclass
from typing import Optional

# NOTE: We intentionally do NOT call load_dotenv() here.
# The runner should not inherit .env files from arbitrary directories
# where it might be launched. Config comes from:
# 1. ~/.skop/config.json (persisted settings)
# 2. Explicit environment variables set by the user


@dataclass
class RunnerConfig:
    """Runner configuration."""

    device_token: Optional[str]
    api_url: str
    ws_url: str
    log_level: str
    config_dir: Path

    @classmethod
    def load(cls) -> "RunnerConfig":
        """Load configuration from file and environment."""
        config_dir = Path.home() / ".skop"
        config_dir.mkdir(exist_ok=True)

        config_file = config_dir / "config.json"

        # Load from file if exists
        file_config = {}
        if config_file.exists():
            try:
                with open(config_file) as f:
                    file_config = json.load(f)
            except json.JSONDecodeError as e:
                # Log warning but continue with defaults - don't crash on corrupt config
                import logging
                logging.getLogger("skop-runner").warning(
                    f"Config file corrupted, using defaults: {e}"
                )
            except Exception as e:
                import logging
                logging.getLogger("skop-runner").warning(
                    f"Could not read config file, using defaults: {e}"
                )

        # Environment variables override file config
        return cls(
            device_token=os.getenv("SKOP_DEVICE_TOKEN") or file_config.get("device_token"),
            api_url=os.getenv("SKOP_API_URL", file_config.get("api_url", "https://skoplabs.com")),
            ws_url=os.getenv("SKOP_WS_URL", file_config.get("ws_url", "wss://skop-relay.fly.dev/runner")),
            log_level=os.getenv("SKOP_LOG_LEVEL", file_config.get("log_level", "INFO")),
            config_dir=config_dir,
        )

    def save(self):
        """Save configuration to file with secure permissions.

        Uses atomic write (write to temp file then rename) to prevent
        corruption if the process is killed mid-write.
        """
        config_file = self.config_dir / "config.json"

        config_data = {
            "device_token": self.device_token,
            "api_url": self.api_url,
            "ws_url": self.ws_url,
            "log_level": self.log_level,
        }

        # Atomic write: write to temp file in same directory, then rename
        # This ensures the config file is never left in a partial state
        try:
            # Create temp file in same directory to ensure same filesystem for atomic rename
            fd, temp_path = tempfile.mkstemp(
                dir=self.config_dir,
                prefix=".config_",
                suffix=".tmp"
            )
            try:
                with os.fdopen(fd, "w") as f:
                    json.dump(config_data, f, indent=2)

                from .compat import secure_file_permissions
                secure_file_permissions(temp_path)

                # Atomic rename
                os.replace(temp_path, config_file)
            except Exception:
                # Clean up temp file on failure
                try:
                    os.unlink(temp_path)
                except OSError:
                    pass
                raise
        except Exception as e:
            # Fallback to direct write if atomic write fails
            import logging
            logging.getLogger("skop-runner").warning(
                f"Atomic config write failed, using direct write: {e}"
            )
            with open(config_file, "w") as f:
                json.dump(config_data, f, indent=2)
            from .compat import secure_file_permissions
            secure_file_permissions(str(config_file))
