"""Local State file patching functionality for electron-angle-patcher."""

from __future__ import annotations

import json
import logging
from typing import TYPE_CHECKING

from electron_angle_patcher.models import AngleVariant, PatchResult

if TYPE_CHECKING:
    from pathlib import Path

logger = logging.getLogger(__name__)


class ChromiumSettingsPatcher:
    """Patches Chromium/Electron Local State files to set ANGLE preferences."""

    def __init__(self, state_file: Path) -> None:
        """Initialize the settings patcher.

        Args:
            state_file: Path to the Local State file.
        """
        self._local_state_file = state_file.expanduser()
        self._desired_key = "use-angle"
        self._desired_value = AngleVariant.OPENGL.value

    def _read_state_file(self) -> dict:
        """Read and parse the Local State file.

        Returns:
            Parsed state dictionary (empty if file doesn't exist or is corrupt).
        """
        if not self._local_state_file.exists():
            logger.info("  Local State missing, creating...")
            self._local_state_file.parent.mkdir(parents=True, exist_ok=True)
            return {}

        logger.info("  Parsing Local State file")
        try:
            return json.loads(self._local_state_file.read_bytes())
        except json.JSONDecodeError:
            logger.warning("  Warning: Local State file is corrupt, creating a new one.")
            return {}

    def _ensure_structure(self, state_data: dict) -> None:
        """Ensure the state data has the required nested structure.

        Args:
            state_data: Dictionary to modify in place.
        """
        state_data.setdefault("browser", {})
        state_data["browser"].setdefault("enabled_labs_experiments", [])

    def _find_and_update_entry(self, experiments: list[str]) -> bool:
        """Find and update existing use-angle entry.

        Args:
            experiments: List of experiment strings to modify.

        Returns:
            True if entry was found and updated, False otherwise.
        """
        for i, entry in enumerate(experiments):
            if "@" not in entry:
                continue

            parts = entry.split("@")
            if len(parts) < 2 or parts[0] != self._desired_key:
                continue

            # Found the key
            if parts[1] == self._desired_value:
                logger.info("  %s@%s is already set", self._desired_key, self._desired_value)
                return True
            else:
                # Value mismatch, update it
                experiments[i] = f"{self._desired_key}@{self._desired_value}"
                logger.info("  Updated %s@%s", self._desired_key, self._desired_value)
                return True

        return False

    def _add_entry_if_missing(self, experiments: list[str]) -> bool:
        """Add use-angle entry if it doesn't exist.

        Args:
            experiments: List to append the entry to.

        Returns:
            True if entry was added, False otherwise.
        """
        entry = f"{self._desired_key}@{self._desired_value}"
        if entry not in experiments:
            experiments.append(entry)
            logger.info("  Added %s@%s", self._desired_key, self._desired_value)
            return True
        return False

    def _write_state_file(self, state_data: dict) -> bool:
        """Write the state data back to the file.

        Args:
            state_data: Dictionary to write.

        Returns:
            True if successful, False otherwise.
        """
        logger.info("  Writing to Local State file")
        try:
            self._local_state_file.write_text(
                json.dumps(state_data, indent=4)
            )
            return True
        except OSError as e:
            logger.error("  Error writing file: %s", e)
            return False

    def patch(self) -> PatchResult:
        """Ensure 'use-angle@1' is set in Chrome's experimental settings.

        Returns:
            PatchResult indicating the outcome.
        """
        state_data = self._read_state_file()
        self._ensure_structure(state_data)

        experiments = state_data["browser"]["enabled_labs_experiments"]

        # Try to update existing entry
        if not self._find_and_update_entry(experiments):
            # Add new entry if not found
            self._add_entry_if_missing(experiments)

        return (
            PatchResult.SUCCESS if self._write_state_file(state_data)
            else PatchResult.ERROR
        )
