"""App bundle construction utilities for integration testing.

This module provides helper functions to create realistic macOS app bundle
structures for testing, including both simple and nested app configurations.
"""

from __future__ import annotations

import json
from pathlib import Path


def create_brave_app_bundle(
    base_dir: Path,
    variant: str = "fresh",
) -> Path:
    """Create a Brave Browser.app bundle for testing.

    Args:
        base_dir: Directory to create the app in.
        variant: Type of app to create:
            - "fresh": Unpatched app, ready for testing
            - "already_patched": Has .original backup and wrapper script
            - "corrupt": Incomplete structure for error testing

    Returns:
        Path to the created app bundle.

    Raises:
        ValueError: If variant is unknown.
    """
    app_path = base_dir / "Brave Browser.app"
    macos_path = app_path / "Contents" / "MacOS"
    macos_path.mkdir(parents=True)

    # Create Info.plist
    info_plist = app_path / "Contents" / "Info.plist"
    info_plist.write_text(
        '<?xml version="1.0" encoding="UTF-8"?>\n'
        '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" '
        '"http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'
        '<plist version="1.0">\n'
        '<dict>\n'
        '    <key>CFBundleExecutable</key>\n'
        '    <string>Brave Browser</string>\n'
        '</dict>\n'
        '</plist>\n'
    )

    # Create PkgInfo
    pkginfo = app_path / "Contents" / "PkgInfo"
    pkginfo.write_text("APPL????\n")

    executable = macos_path / "Brave Browser"

    if variant == "fresh":
        # Create a fake executable (not a script to avoid wrapper detection)
        # Real macOS executables are Mach-O binaries, not scripts
        executable.write_bytes(b"FAKE EXECUTABLE\n")
        executable.chmod(0o755)

    elif variant == "already_patched":
        # Create the backup (fake executable)
        original = macos_path / "Brave Browser.original"
        original.write_bytes(b"FAKE EXECUTABLE\n")
        original.chmod(0o755)

        # Create the wrapper
        executable.write_text(
            "#!/bin/bash\n"
            'DIR="$(cd "$(dirname "$0")" && pwd)"\n'
            'exec "$DIR/Brave Browser.original" --use-angle=gl "$@"\n'
        )
        executable.chmod(0o755)

    elif variant == "corrupt":
        # Missing executable - for error testing
        pass

    else:
        raise ValueError(f"Unknown variant: {variant}")

    return app_path


def create_lghub_app_bundle(
    base_dir: Path,
    variant: str = "fresh",
) -> Path:
    """Create a lghub.app bundle with nested Electron app for testing.

    The lghub structure is complex:
    - lghub.app/Contents/MacOS/lghub (Qt app, not patched)
    - lghub.app/Contents/MacOS/lghub_ui.app/ (Electron app, gets patched)

    Args:
        base_dir: Directory to create the app in.
        variant: Type of app to create:
            - "fresh": Unpatched app, ready for testing
            - "already_patched": Has .original backup and wrapper script
            - "corrupt": Incomplete structure for error testing

    Returns:
        Path to the created app bundle.

    Raises:
        ValueError: If variant is unknown.
    """
    app_path = base_dir / "lghub.app"
    macos_path = app_path / "Contents" / "MacOS"
    macos_path.mkdir(parents=True)

    # Create the main Qt executable (not patched)
    lghub_exe = macos_path / "lghub"
    lghub_exe.write_text(
        "#!/bin/bash\n"
        "# lghub Qt executable stub\n"
        "exit 0\n"
    )
    lghub_exe.chmod(0o755)

    # Create the nested Electron app
    electron_app = macos_path / "lghub_ui.app"
    electron_macos = electron_app / "Contents" / "MacOS"
    electron_macos.mkdir(parents=True)

    # Create Info.plist for nested app
    info_plist = electron_app / "Contents" / "Info.plist"
    info_plist.write_text(
        '<?xml version="1.0" encoding="UTF-8"?>\n'
        '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" '
        '"http://www.apple.com/DTDs/PropertyList-1.0.dtd">\n'
        '<plist version="1.0">\n'
        '<dict>\n'
        '    <key>CFBundleExecutable</key>\n'
        '    <string>lghub_ui</string>\n'
        '</dict>\n'
        '</plist>\n'
    )

    electron_exe = electron_macos / "lghub_ui"

    if variant == "fresh":
        # Create a fake executable (not a script to avoid wrapper detection)
        electron_exe.write_bytes(b"FAKE EXECUTABLE\n")
        electron_exe.chmod(0o755)

    elif variant == "already_patched":
        # Create the backup (fake executable)
        original = electron_macos / "lghub_ui.original"
        original.write_bytes(b"FAKE ELECTRON EXECUTABLE\n")
        original.chmod(0o755)

        # Create the wrapper
        electron_exe.write_text(
            "#!/bin/bash\n"
            'DIR="$(cd "$(dirname "$0")" && pwd)"\n'
            'exec "$DIR/lghub_ui.original" --use-angle=gl "$@"\n'
        )
        electron_exe.chmod(0o755)

    elif variant == "corrupt":
        # Missing nested executable - for error testing
        pass

    else:
        raise ValueError(f"Unknown variant: {variant}")

    return app_path


def create_local_state_file(
    app_support_dir: Path,
    app_name: str,
    content: str = "empty",
) -> Path:
    """Create a Local State file for testing.

    Args:
        app_support_dir: Application Support directory.
        app_name: Name of the app (e.g., "Brave Browser", "lghub").
        content: Type of content to create:
            - "empty": Empty experiments array
            - "with_angle": Has wrong angle value (e.g., use-angle@0)
            - "corrupt": Invalid JSON
            - "partial": Missing browser section

    Returns:
        Path to the created Local State file.

    Raises:
        ValueError: If content type is unknown.
    """
    app_dir = app_support_dir / app_name
    app_dir.mkdir(parents=True, exist_ok=True)
    state_file = app_dir / "Local State"

    if content == "empty":
        data = {"browser": {"enabled_labs_experiments": []}}
        state_file.write_text(json.dumps(data, indent=4))

    elif content == "with_angle":
        data = {
            "browser": {
                "enabled_labs_experiments": [
                    "use-angle@0",  # Wrong value, should be @1
                    "other-feature@2",
                ]
            }
        }
        state_file.write_text(json.dumps(data, indent=4))

    elif content == "already_correct":
        data = {
            "browser": {
                "enabled_labs_experiments": [
                    "use-angle@1",  # Already correct
                    "other-feature@2",
                ]
            }
        }
        state_file.write_text(json.dumps(data, indent=4))

    elif content == "corrupt":
        state_file.write_text("{invalid json content")

    elif content == "partial":
        # Missing browser section
        data = {"some_other_key": "value"}
        state_file.write_text(json.dumps(data, indent=4))

    else:
        raise ValueError(f"Unknown content type: {content}")

    return state_file


def create_multi_app_scenario(
    temp_dir: Path,
    scenario: str = "standard",
) -> dict[str, Path]:
    """Create complex multi-app test scenarios.

    Args:
        temp_dir: Temporary directory for the scenario.
        scenario: Type of scenario to create:
            - "standard": A few standard apps in Application Support
            - "nested": Apps in nested directories
            - "mixed": Mix of valid and invalid apps
            - "containers": Apps in macOS Containers

    Returns:
        Dictionary mapping app names to their Local State file paths.
    """
    result = {}

    if scenario == "standard":
        # Create a few standard apps
        support_dir = temp_dir / "Application Support"
        result["Brave"] = create_local_state_file(
            support_dir, "Brave", "with_angle"
        )
        result["Discord"] = create_local_state_file(
            support_dir, "discord", "empty"
        )
        result["Slack"] = create_local_state_file(
            support_dir, "Slack", "already_correct"
        )

    elif scenario == "nested":
        # Create apps in nested directories
        support_dir = temp_dir / "Library" / "Application Support"
        result["Teams"] = create_local_state_file(
            support_dir / "Microsoft" / "Teams",
            "EBWebView",
            "with_angle",
        )
        result["Edge"] = create_local_state_file(
            support_dir / "Microsoft Edge",
            "Default",
            "empty",
        )

    elif scenario == "mixed":
        # Mix of valid and invalid scenarios
        support_dir = temp_dir / "Application Support"
        result["Valid1"] = create_local_state_file(
            support_dir, "App1", "with_angle"
        )
        result["Corrupt"] = create_local_state_file(
            support_dir, "App2", "corrupt"
        )
        result["Valid2"] = create_local_state_file(
            support_dir, "App3", "empty"
        )

    elif scenario == "containers":
        # Apps in macOS Containers structure
        containers_dir = temp_dir / "Library" / "Containers"
        app_container = (
            containers_dir / "com.example.app" / "Data" / "Library" / "Application Support"
        )
        result["ContainerApp"] = create_local_state_file(
            app_container, "MyApp", "with_angle"
        )

    else:
        raise ValueError(f"Unknown scenario: {scenario}")

    return result
