import json
import queue
import time
import unittest
from unittest.mock import MagicMock, patch

from esp_viewer.core.backend import DeviceService
from esp_viewer.core.chip_info import ChipInfoManager
from esp_viewer.core.protocol import CommandType, EventType, Packet


class TestChipInfo(unittest.TestCase):
    def test_manager_parsing(self):
        # Mock subprocess.run for esptool chip_id
        with patch("subprocess.run") as mock_run:
            mock_run.return_value.returncode = 0
            mock_run.return_value.stdout = """esptool.py v4.8.1
Chip is ESP32-D0WDQ6 (revision v1.0)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 30:ae:a4:cc:23:44
"""
            manager = ChipInfoManager("/dev/ttyUSB0")
            summary = manager._get_chip_summary()

            self.assertEqual(summary["model"], "ESP32-D0WDQ6")
            self.assertEqual(summary["revision"], "v1.0")
            self.assertEqual(summary["mac"], "30:ae:a4:cc:23:44")
            self.assertIn("WiFi", summary["features"])
            self.assertIn("raw", summary)
            self.assertIn("Chip is ESP32-D0WDQ6", summary["raw"])

    def test_mock_integration(self):
        cmd_q = queue.Queue()
        evt_q = queue.Queue()
        profile = {
            "meta": {"name": "Test", "mock_type": "data"},
            "parameters": [],
            "streams": [],
        }

        service = DeviceService(cmd_q, evt_q, profile)

        # Use real MockDevice but don't open it (don't start threads)
        from esp_viewer.core.mock_device import MockDevice

        service.device_interface = MockDevice(port="MOCK", profile=profile)

        # Send GET_CHIP_INFO command
        service._handle_command(Packet(CommandType.GET_CHIP_INFO))

        # Check event queue for CHIP_INFO_RECEIVED
        found = False
        while not evt_q.empty():
            pkt = evt_q.get()
            if pkt.type == EventType.CHIP_INFO_RECEIVED:
                found = True
                self.assertIsInstance(pkt.payload, dict)
                self.assertIn("chip", pkt.payload)
                break

        self.assertTrue(found, "CHIP_INFO_RECEIVED event not found in queue")

    def test_mock_app_info(self):
        """Merged from test_backend_local.py: Verifies app info retrieval from mock device."""
        cmd_q = queue.Queue()
        evt_q = queue.Queue()
        service = DeviceService(cmd_q, evt_q, {"name": "test"})
        from esp_viewer.core.mock_device import MockDevice
        service.device_interface = MockDevice(None, {})
        
        service._get_app_info([])
        
        found = False
        while not service.event_queue.empty():
            packet = service.event_queue.get()
            if packet.type == EventType.APP_INFO_RECEIVED:
                self.assertIn("apps", packet.payload)
                self.assertEqual(len(packet.payload["apps"]), 1)
                found = True
                break
        self.assertTrue(found, "APP_INFO_RECEIVED event not found")

    def test_mock_firmware_read(self):
        """Merged from test_backend_local.py: Verifies firmware reading from mock device."""
        cmd_q = queue.Queue()
        evt_q = queue.Queue()
        service = DeviceService(cmd_q, evt_q, {"name": "test"})
        from esp_viewer.core.mock_device import MockDevice
        service.device_interface = MockDevice(None, {})
        
        service._read_firmware({"offset": "0x0", "size": "0x1000", "filename": "test.bin"})
        
        found = False
        while not service.event_queue.empty():
            packet = service.event_queue.get()
            if packet.type == EventType.FIRMWARE_READ_COMPLETE:
                self.assertEqual(packet.payload["status"], "success")
                found = True
                break
        self.assertTrue(found, "FIRMWARE_READ_COMPLETE event not found")


class TestChipInfoIntegration(unittest.TestCase):
    def test_real_device_esptool(self):
        import os
        real_port = os.environ.get("REAL_PORT")
        if not real_port:
            self.skipTest("Skipping real device test since REAL_PORT is not set")
        
        manager = ChipInfoManager(real_port)
        summary = manager._get_chip_summary()
        self.assertIsInstance(summary, dict)
        self.assertIn("raw", summary)
        print("\n[Real Device Chip Info Output]")
        print(summary.get("raw", "None"))


if __name__ == "__main__":
    unittest.main()
