"""Pure regression fixtures for the proven ConfigInfo file-SHA1 map rewrite."""

from __future__ import annotations

import base64
import hashlib
import sys
import zlib
from pathlib import Path


ROOT = Path(__file__).resolve().parents[2]
CONNECTOR = ROOT / "plugins" / "1c" / "connector"
PARSER = ROOT / "plugins" / "1c"
for path in (CONNECTOR, PARSER):
    if str(path) not in sys.path:
        sys.path.insert(0, str(path))

import adapter_1c_server as adapter  # noqa: E402
from parser.payload import decode_payload_lossless  # noqa: E402


LOGICAL = "77494708-43ea-4956-ac3c-199cfb035ad2.0"


def raw_deflate(text: str) -> bytes:
    encoder = zlib.compressobj(wbits=-zlib.MAX_WBITS)
    return encoder.compress(text.encode("utf-8")) + encoder.flush()


def test_rewrites_only_named_file_sha1_reference() -> None:
    original_file = b"old module bytes"
    replacement_file = b"new module bytes"
    old_ref = base64.b64encode(hashlib.sha1(original_file).digest()).decode("ascii")
    service_atom = base64.b64encode(b"S" * 32).decode("ascii")
    source_text = f'{{2,extension,{service_atom}}},{{7,"{LOGICAL}",{old_ref},"other.0",{old_ref}}}'
    result = adapter.rewrite_extension_configinfo_file_sha1_reference(
        raw_deflate(source_text), logical_file_name=LOGICAL, replacement_file_data=replacement_file
    )
    assert result["status"] == "ok"
    assert result["replacement_file_sha1"] == hashlib.sha1(replacement_file).hexdigest()
    decoded = str(decode_payload_lossless(result["payload"]).get("text") or "")
    assert service_atom in decoded
    assert result["replacement_reference_base64"] in decoded
    assert decoded.count(old_ref) == 1  # unrelated map entry was preserved


def test_rejects_ambiguous_logical_reference() -> None:
    ref = base64.b64encode(hashlib.sha1(b"old").digest()).decode("ascii")
    source_text = f'{{7,"{LOGICAL}",{ref},"{LOGICAL}",{ref}}}'
    result = adapter.rewrite_extension_configinfo_file_sha1_reference(
        raw_deflate(source_text), logical_file_name=LOGICAL, replacement_file_data=b"new"
    )
    assert result["status"] == "reference_not_unique"
    assert result["occurrences"] == 2


def test_builds_paired_plan_only_when_map_matches_current_stream() -> None:
    current = b"current module"
    replacement = b"replacement module"
    current_ref = base64.b64encode(hashlib.sha1(current).digest()).decode("ascii")
    configinfo = raw_deflate(f'{{7,"{LOGICAL}",{current_ref}}}')
    result = adapter.build_extension_saved_state_pair_plan(
        logical_file_name=LOGICAL,
        current_file_data=current,
        replacement_file_data=replacement,
        current_configinfo_data=configinfo,
    )
    assert result["status"] == "ok"
    assert result["module"]["replacement_sha1"] == hashlib.sha1(replacement).hexdigest()
    assert result["configinfo"]["service_atoms"] == "preserved_unmodified"


def test_rejects_pair_when_map_points_to_another_stream() -> None:
    mapped = b"other module"
    current = b"current module"
    mapped_ref = base64.b64encode(hashlib.sha1(mapped).digest()).decode("ascii")
    configinfo = raw_deflate(f'{{7,"{LOGICAL}",{mapped_ref}}}')
    result = adapter.build_extension_saved_state_pair_plan(
        logical_file_name=LOGICAL,
        current_file_data=current,
        replacement_file_data=b"replacement",
        current_configinfo_data=configinfo,
    )
    assert result["status"] == "configinfo_reference_mismatch"


class FakeCursor:
    def __init__(self, state: dict[str, bytes]) -> None:
        self.state = state
        self.rows: list[dict[str, object]] = []

    def execute(self, sql: str, params: tuple[object, ...] | None = None) -> None:
        if sql.startswith("SET LOCK_TIMEOUT"):
            return
        if sql.startswith("SELECT FileName, PartNo, BinaryData"):
            assert params is not None
            self.rows = [
                {"FileName": name, "PartNo": 0, "BinaryData": self.state[name]}
                for name in params
                if name in self.state
            ]
            return
        if sql.startswith("UPDATE dbo.ConfigCASSave"):
            assert params is not None
            data, _size, name, _part = params
            self.state[str(name)] = bytes(data)
            return
        raise AssertionError(sql)

    def fetchall(self) -> list[dict[str, object]]:
        return self.rows


class FakeConnection:
    def __init__(self, state: dict[str, bytes]) -> None:
        self.cursor_instance = FakeCursor(state)
        self.committed = False
        self.rolled_back = False
        self.closed = False

    def cursor(self, **_kwargs: object) -> FakeCursor:
        return self.cursor_instance

    def commit(self) -> None:
        self.committed = True

    def rollback(self) -> None:
        self.rolled_back = True

    def close(self) -> None:
        self.closed = True


def install_fake_pair_sql(monkeypatch: object, state: dict[str, bytes], connection: FakeConnection) -> None:
    monkeypatch.setattr(adapter, "connect_live_sql", lambda *_args, **_kwargs: (connection, {"database": "test"}, None))
    monkeypatch.setattr(
        adapter,
        "read_storage_file_bytes",
        lambda _base, _table, name, **_kwargs: (state.get(name), {"database": "test"}, None if name in state else {"status": "missing"}),
    )
    monkeypatch.setattr(adapter, "write_storage_apply_backup", lambda **_kwargs: {"backup_id": "test"})
    monkeypatch.setattr(adapter, "invalidate_adapter_caches_after_saved_state_change", lambda *_args, **_kwargs: {"invalidated": True})


def test_atomically_updates_module_and_configinfo(monkeypatch: object) -> None:
    extension = "fb26cf42-7609-11f1-828f-005056b0d483"
    module_name = f"{extension}__{LOGICAL}"
    configinfo_name = f"{extension}__configinfo"
    current = b"current module"
    current_ref = base64.b64encode(hashlib.sha1(current).digest()).decode("ascii")
    state = {module_name: current, configinfo_name: raw_deflate(f'{{7,"{LOGICAL}",{current_ref}}}')}
    connection = FakeConnection(state)
    install_fake_pair_sql(monkeypatch, state, connection)

    result = adapter.apply_extension_saved_state_pair(
        "upo_test",
        module_file_name=module_name,
        replacement_module_data=b"new module",
        expected_module_sha1=hashlib.sha1(current).hexdigest(),
        proposal={"method": "test"},
    )

    assert result["status"] == "applied"
    assert result["applied"] is True
    assert connection.committed is True
    assert result["configurator_refresh"]["action"] == "close_reopen_object"
    map_text = str(decode_payload_lossless(state[configinfo_name]).get("text") or "")
    assert base64.b64encode(hashlib.sha1(b"new module").digest()).decode("ascii") in map_text


def test_atomic_writer_rolls_back_when_configinfo_map_diverges(monkeypatch: object) -> None:
    extension = "fb26cf42-7609-11f1-828f-005056b0d483"
    module_name = f"{extension}__{LOGICAL}"
    configinfo_name = f"{extension}__configinfo"
    current = b"current module"
    wrong_ref = base64.b64encode(hashlib.sha1(b"other module").digest()).decode("ascii")
    state = {module_name: current, configinfo_name: raw_deflate(f'{{7,"{LOGICAL}",{wrong_ref}}}')}
    connection = FakeConnection(state)
    install_fake_pair_sql(monkeypatch, state, connection)

    result = adapter.apply_extension_saved_state_pair(
        "upo_test",
        module_file_name=module_name,
        replacement_module_data=b"new module",
        expected_module_sha1=hashlib.sha1(current).hexdigest(),
        proposal={"method": "test"},
    )

    assert result["status"] == "configinfo_reference_mismatch"
    assert result["applied"] is False
    assert connection.rolled_back is True
    assert state[module_name] == current
