# SPDX-License-Identifier: AGPL-3.0-only
# Copyright (c) 2026 sol pbc

from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import Mock

from solstone.think.push import devices
from tests.helpers.module_mocks import module_mock


def _devices_path(tmp_path: Path) -> Path:
    return tmp_path / "config" / "push_devices.json"


def _register(
    fingerprint: str,
    token: str,
    *,
    bundle_id: str = "org.solpbc.solstone-swift",
    environment: str = "development",
    platform: str = "ios",
) -> int:
    return devices.register_device(
        fingerprint=fingerprint,
        token=token,
        bundle_id=bundle_id,
        environment=environment,
        platform=platform,
    )


def test_load_devices_returns_empty_for_missing_store(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))

    assert devices.load_devices() == []


def test_register_one_device_stores_fingerprint_row(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))
    monkeypatch.setattr(
        devices,
        "time",
        module_mock(devices.time, time=Mock(return_value=1000)),
    )

    count = _register("fp-1", "a" * 64)

    assert count == 1
    assert devices.load_devices() == [
        {
            "fingerprint": "fp-1",
            "token": "a" * 64,
            "bundle_id": "org.solpbc.solstone-swift",
            "environment": "development",
            "platform": "ios",
            "registered_at": 1000,
        }
    ]
    assert "device_pubkey" not in devices.load_devices()[0]


def test_register_same_fingerprint_replaces_row(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))
    monkeypatch.setattr(
        devices,
        "time",
        module_mock(devices.time, time=Mock(side_effect=[1000, 2000])),
    )

    first = _register("fp-1", "a" * 64)
    second = _register("fp-1", "b" * 64, environment="production")

    assert first == 1
    assert second == 1
    assert devices.load_devices() == [
        {
            "fingerprint": "fp-1",
            "token": "b" * 64,
            "bundle_id": "org.solpbc.solstone-swift",
            "environment": "production",
            "platform": "ios",
            "registered_at": 2000,
        }
    ]


def test_two_fingerprints_coexist(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))

    assert _register("fp-1", "a" * 64) == 1
    assert _register("fp-2", "b" * 64) == 2

    assert {device["fingerprint"] for device in devices.load_devices()} == {
        "fp-1",
        "fp-2",
    }


def test_one_token_maps_to_one_device(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))
    token = "c" * 64

    assert _register("fp-1", token) == 1
    assert _register("fp-2", token) == 1

    stored = devices.load_devices()
    assert stored == [
        {
            "fingerprint": "fp-2",
            "token": token,
            "bundle_id": "org.solpbc.solstone-swift",
            "environment": "development",
            "platform": "ios",
            "registered_at": stored[0]["registered_at"],
        }
    ]


def test_remove_device_by_fingerprint(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))
    _register("fp-1", "a" * 64)
    _register("fp-2", "b" * 64)

    assert devices.remove_device("fp-1") is True
    assert [device["fingerprint"] for device in devices.load_devices()] == ["fp-2"]

    assert devices.remove_device("missing") is False
    assert [device["fingerprint"] for device in devices.load_devices()] == ["fp-2"]


def test_remove_devices_by_tokens_removes_matching_subset(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))
    _register("fp-1", "a" * 64)
    _register("fp-2", "b" * 64)
    _register("fp-3", "c" * 64)

    removed = devices.remove_devices_by_tokens({"a" * 64, "c" * 64})

    assert removed == 2
    assert [device["fingerprint"] for device in devices.load_devices()] == ["fp-2"]


def test_remove_devices_by_tokens_unknown_token_noops(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))
    _register("fp-1", "a" * 64)
    before = devices.load_devices()

    removed = devices.remove_devices_by_tokens({"z" * 64})

    assert removed == 0
    assert devices.load_devices() == before


def test_remove_devices_by_tokens_empty_set_noops(monkeypatch, tmp_path):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))

    removed = devices.remove_devices_by_tokens(set())

    assert removed == 0
    assert not _devices_path(tmp_path).exists()


def test_load_devices_returns_empty_for_legacy_token_keyed_store(
    monkeypatch, tmp_path, caplog
):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))
    path = _devices_path(tmp_path)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(
        json.dumps(
            {
                "devices": [
                    {
                        "token": "a" * 64,
                        "bundle_id": "org.solpbc.solstone-swift",
                        "environment": "development",
                        "platform": "ios",
                        "registered_at": 1,
                    }
                ]
            }
        ),
        encoding="utf-8",
    )

    assert devices.load_devices() == []
    assert "push device store unreadable" in caplog.text


def test_load_devices_returns_empty_for_malformed_store(monkeypatch, tmp_path, caplog):
    monkeypatch.setenv("SOLSTONE_JOURNAL", str(tmp_path))
    path = _devices_path(tmp_path)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(json.dumps({"devices": "bad"}), encoding="utf-8")

    assert devices.load_devices() == []
    assert "push device store unreadable" in caplog.text


def test_status_view_masks_token_and_formats_timestamp():
    assert devices.status_view(
        {
            "fingerprint": "fp-1",
            "token": "a" * 60 + "bcde",
            "bundle_id": "org.solpbc.solstone-swift",
            "environment": "development",
            "platform": "ios",
            "registered_at": 1713528000,
        }
    ) == {
        "token_suffix": "...bcde",
        "bundle_id": "org.solpbc.solstone-swift",
        "environment": "development",
        "platform": "ios",
        "registered_at": "2024-04-19T12:00:00Z",
    }
