"""Main application class for electron-angle-patcher."""

from __future__ import annotations

import logging
from pathlib import Path

from electron_angle_patcher.config import Config
from electron_angle_patcher.executable_patcher import (
    BraveExecutablePatcher,
    ChromeExecutablePatcher,
    LghubPatcher,
)
from electron_angle_patcher.models import PatchResult, PatchSummary
from electron_angle_patcher.scanner import LocalStateScanner
from electron_angle_patcher.settings_patcher import ChromiumSettingsPatcher
from electron_angle_patcher.utils import kill_app_by_name

logger = logging.getLogger(__name__)


class ElectronAnglePatcher:
    """Main application class for patching Electron/Chromium apps."""

    def __init__(
        self,
        brave_path: Path = Config.DEFAULT_BRAVE_PATH,
        chrome_path: Path = Config.DEFAULT_CHROME_PATH,
        lghub_path: Path = Config.DEFAULT_LGHUB_PATH,
    ) -> None:
        """Initialize the patcher application.

        Args:
            brave_path: Path to Brave Browser.app.
            chrome_path: Path to Google Chrome.app.
            lghub_path: Path to lghub.app.
        """
        self._brave_patcher = BraveExecutablePatcher(brave_path)
        self._chrome_patcher = ChromeExecutablePatcher(chrome_path)
        self._lghub_patcher = LghubPatcher(lghub_path)
        self._scanner = LocalStateScanner()
        self._summary = PatchSummary()

    def _patch_executable_app(
        self,
        patcher: BraveExecutablePatcher | ChromeExecutablePatcher | LghubPatcher,
        app_name: str,
        list_only: bool,
    ) -> None:
        """Patch an executable-based application.

        Args:
            patcher: The patcher instance to use.
            app_name: Name of the application.
            list_only: If True, only list the app without patching.
        """

        app_path = getattr(patcher, "_wrapper", patcher).app_path

        if not app_path.exists():
            logger.info("%s not found at %s", app_name, app_path)
            self._summary.not_found.append(app_name)
            return

        original_path = getattr(patcher, "_wrapper", patcher).original_path
        is_patched = original_path.exists()

        if list_only:
            status = "already patched" if is_patched else "not patched"
            logger.info("Found %s (%s)", app_name, status)
            self._summary.already_patched.append(app_name) if is_patched else self._summary.not_found.append(app_name)
        else:
            # Kill the app before patching to avoid file locks
            kill_app_by_name(app_name)
            result = patcher.patch()
            if result == PatchResult.SUCCESS:
                self._summary.successful.append(app_name)
            elif result == PatchResult.ALREADY_PATCHED:
                self._summary.already_patched.append(app_name)
            else:
                self._summary.failed.append(app_name)

    def _patch_specific_apps(self, list_only: bool) -> None:
        """Patch specific/complex application paths.

        Args:
            list_only: If True, only list apps without patching.
        """
        logger.info("Checking specific/complex application paths...")

        for app_name, state_path in Config.SPECIFIC_APPS.items():
            expanded_path = state_path.expanduser()

            if not expanded_path.exists():
                continue

            if list_only:
                logger.info("Found %s: %s", app_name, expanded_path)
            else:
                logger.info("Patching %s", app_name)
                # Kill the app before patching to avoid file locks
                kill_app_by_name(app_name)
                patcher = ChromiumSettingsPatcher(expanded_path)
                result = patcher.patch()
                if result == PatchResult.SUCCESS:
                    self._summary.successful.append(app_name)
                else:
                    self._summary.failed.append(app_name)

    def _scan_and_patch(
        self,
        scan_dirs: list[Path],
        list_only: bool,
        skip_patterns: frozenset[str],
    ) -> None:
        """Scan directories and patch discovered apps.

        Args:
            scan_dirs: List of directories to scan.
            list_only: If True, only list apps without patching.
            skip_patterns: Patterns to skip when scanning.
        """
        scanner = LocalStateScanner(skip_patterns=skip_patterns)

        for directory in scan_dirs:
            expanded_dir = directory.expanduser()

            if not expanded_dir.exists():
                continue

            apps = scanner.scan(expanded_dir)

            for app in apps:
                if list_only:
                    logger.info("Found %s: %s", app.name, app.state_file)
                else:
                    logger.info("Patching %s", app.name)
                    # Kill the app before patching to avoid file locks
                    kill_app_by_name(app.name)
                    patcher = ChromiumSettingsPatcher(app.state_file)
                    result = patcher.patch()
                    if result == PatchResult.SUCCESS:
                        self._summary.successful.append(app.name)
                    else:
                        self._summary.failed.append(app.name)

    def run(
        self,
        list_only: bool = False,
        deep_scan: bool = False,
    ) -> PatchSummary:
        """Run the main patching routine.

        Args:
            list_only: If True, only list apps without patching.
            deep_scan: If True, perform deep scan of home directory.

        Returns:
            PatchSummary with operation results.
        """
        # Handle Brave Browser
        logger.info("Checking Brave Browser...")
        self._patch_executable_app(self._brave_patcher, "Brave Browser", list_only)
        logger.info("")

        # Handle Google Chrome
        logger.info("Checking Google Chrome...")
        self._patch_executable_app(self._chrome_patcher, "Google Chrome", list_only)
        logger.info("")

        # Handle lghub
        logger.info("Checking lghub...")
        self._patch_executable_app(self._lghub_patcher, "lghub", list_only)
        logger.info("")

        # Patch specific apps
        self._patch_specific_apps(list_only)

        # Deep scan or standard scan
        if deep_scan:
            logger.info("")
            logger.info("Performing deep scan for Local State files in Home directory...")
            self._scan_and_patch(
                [Path("~/")],
                list_only,
                Config.DEEP_SCAN_SKIP_PATTERNS,
            )
        else:
            logger.info("")
            logger.info("Scanning standard macOS directories...")
            scan_dirs = [Path(d) for d in Config.STANDARD_SCAN_DIRS]
            self._scan_and_patch(
                scan_dirs,
                list_only,
                Config.STANDARD_SCAN_SKIP_PATTERNS,
            )

        return self._summary
