"""KNX Telegrams Migration Tests."""

from __future__ import annotations

import os
from typing import Any

from knx_telegram_store import TelegramQuery

from homeassistant.components.knx.const import DOMAIN, KNX_MODULE_KEY
from homeassistant.core import HomeAssistant
from homeassistant.helpers.storage import Store

from .conftest import KNXTestKit

from tests.common import async_load_json_object_fixture


async def test_migrate_telegrams_json_to_sqlite(
    hass: HomeAssistant,
    knx: KNXTestKit,
) -> None:
    """Test migrating telegrams from legacy JSON to SQLite."""
    store = Store[dict[str, Any]](hass, version=1, key="knx/telegrams_history.json")
    legacy_path = store.path

    legacy_data = await async_load_json_object_fixture(
        hass, "telegrams_history.json", DOMAIN
    )

    # The legacy KNX store saved the telegram list directly, so async_load()
    # returns the list. Save the inner list, not the fixture wrapper dict.
    await store.async_save(legacy_data["data"])

    await knx.setup_integration(real_telegram_store=True)
    telegrams_module = hass.data[KNX_MODULE_KEY].telegrams

    await hass.async_block_till_done()

    # Verify migration
    assert telegrams_module.store is not None
    result = await telegrams_module.store.query(TelegramQuery(order_descending=False))
    assert len(result.telegrams) == 10

    # Check normalization: [0] -> (0,)
    # Note: Backend might return list even if stored as tuple due to JSON serialization
    assert result.telegrams[0].destination == "3/2/100"
    payload_0 = result.telegrams[0].payload
    assert isinstance(payload_0, (list, tuple))
    assert tuple(payload_0) == (0,)

    # Check normalization: [7, 158] -> (7, 158)
    assert result.telegrams[2].destination == "1/2/11"
    payload_2 = result.telegrams[2].payload
    assert isinstance(payload_2, (list, tuple))
    assert tuple(payload_2) == (7, 158)

    # Check None payload stays None
    assert result.telegrams[3].destination == "3/7/62"
    assert result.telegrams[3].payload is None

    # Check int payload stays int
    assert result.telegrams[4].destination == "1/4/100"
    assert result.telegrams[4].payload == 1

    # Check long string payload
    assert result.telegrams[6].destination == "0/6/0"
    payload_6 = result.telegrams[6].payload
    assert isinstance(payload_6, (list, tuple))
    assert tuple(payload_6) == (
        77,
        53,
        32,
        83,
        48,
        32,
        65,
        51,
        51,
        53,
        32,
        69,
        48,
        48,
    )

    # Verify legacy file removal
    assert not os.path.exists(legacy_path)


async def test_migrate_telegrams_json_missing_keys(
    hass: HomeAssistant,
    knx: KNXTestKit,
) -> None:
    """Test migrating telegrams from legacy JSON missing fields (e.g., data_secure)."""
    store = Store[dict[str, Any]](hass, version=1, key="knx/telegrams_history.json")
    legacy_path = store.path

    legacy_data = [
        {
            "destination": "3/2/100",
            "source": "1.0.6",
            "direction": "Incoming",
            "payload": [0],
            "telegramtype": "GroupValueWrite",
            "timestamp": "2026-05-07T23:34:45.127015+02:00",
            "value": 0,
        }
    ]

    await store.async_save(legacy_data)

    await knx.setup_integration(real_telegram_store=True)
    telegrams_module = hass.data[KNX_MODULE_KEY].telegrams

    await hass.async_block_till_done()

    # Verify migration
    assert telegrams_module.store is not None
    result = await telegrams_module.store.query(TelegramQuery(order_descending=False))
    assert len(result.telegrams) == 1

    # Check that data_secure defaults to False/None as appropriate, and others default to None or empty string
    assert result.telegrams[0].destination == "3/2/100"
    assert result.telegrams[0].data_secure is False
    assert result.telegrams[0].source_name == ""
    assert result.telegrams[0].destination_name == ""
    assert result.telegrams[0].dpt_main is None
    assert result.telegrams[0].dpt_sub is None

    # Verify legacy file removal
    assert not os.path.exists(legacy_path)
