from __future__ import annotations

import importlib.util
import plistlib
import sqlite3
from pathlib import Path
from types import ModuleType, SimpleNamespace

import pytest

REPOSITORY_ROOT = Path(__file__).parents[1]
MODULE_PATH = (
    REPOSITORY_ROOT
    / "plugins"
    / "xgrids-k1"
    / "lab"
    / "iphone-capture"
    / "targeted_profile_backup.py"
)


def _load_module() -> ModuleType:
    spec = importlib.util.spec_from_file_location("targeted_profile_backup", MODULE_PATH)
    assert spec is not None
    assert spec.loader is not None
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    return module


TARGETED = _load_module()


def _synthetic_backup(tmp_path: Path, payload: bytes) -> Path:
    device = tmp_path / "device"
    device.mkdir()
    (device / "Manifest.plist").write_bytes(
        plistlib.dumps({"IsEncrypted": False}, fmt=plistlib.FMT_BINARY)
    )
    file_id = TARGETED.PREFERENCES_FILE_ID
    source = device / file_id[:2] / file_id
    source.parent.mkdir()
    source.write_bytes(payload)
    with sqlite3.connect(device / "Manifest.db") as connection:
        connection.execute(
            "CREATE TABLE Files (fileID TEXT, domain TEXT, relativePath TEXT)"
        )
        connection.execute(
            "INSERT INTO Files VALUES (?, ?, ?)",
            (file_id, TARGETED.APP_DOMAIN, TARGETED.PREFERENCES_PATH),
        )
    return device


def test_profile_filter_is_exact_to_lixelgo_preferences() -> None:
    assert TARGETED._is_preferences_backup_file(
        SimpleNamespace(
            file_name=None,
            device_name=None,
            domain=TARGETED.APP_DOMAIN,
            relative_path=TARGETED.PREFERENCES_PATH,
        )
    )
    assert not TARGETED._is_preferences_backup_file(
        SimpleNamespace(
            file_name=None,
            device_name=None,
            domain=TARGETED.APP_DOMAIN,
            relative_path="Documents/large-project.las",
        )
    )
    assert not TARGETED._is_preferences_backup_file(
        SimpleNamespace(
            file_name=None,
            device_name=None,
            domain="AppDomain-com.example.Other",
            relative_path=TARGETED.PREFERENCES_PATH,
        )
    )


def test_profile_file_id_filter_matches_only_the_exact_backup_payload() -> None:
    file_id = TARGETED.PREFERENCES_FILE_ID
    assert TARGETED._is_preferences_backup_file(
        SimpleNamespace(file_name=f"device/{file_id[:2]}/{file_id}")
    )
    assert TARGETED._is_preferences_backup_file(
        SimpleNamespace(file_name=None, device_name=f"device/{file_id[:2]}/{file_id}")
    )
    assert not TARGETED._is_preferences_backup_file(
        SimpleNamespace(file_name=f"device/{file_id[:2]}/{file_id}0")
    )
    assert not TARGETED._is_preferences_backup_file(
        SimpleNamespace(file_name="device/aa/" + "a" * 40)
    )


def test_read_preferences_accepts_one_small_unencrypted_plist(tmp_path: Path) -> None:
    payload = plistlib.dumps({"opaque-key": "opaque-value"}, fmt=plistlib.FMT_BINARY)
    device = _synthetic_backup(tmp_path, payload)

    assert TARGETED._read_preferences(device) == payload


def test_read_preferences_rejects_encrypted_backup(tmp_path: Path) -> None:
    payload = plistlib.dumps({"opaque-key": "opaque-value"}, fmt=plistlib.FMT_BINARY)
    device = _synthetic_backup(tmp_path, payload)
    (device / "Manifest.plist").write_bytes(
        plistlib.dumps({"IsEncrypted": True}, fmt=plistlib.FMT_BINARY)
    )

    with pytest.raises(TARGETED.TargetedProfileBackupError, match="encrypted"):
        TARGETED._read_preferences(device)
