from unittest.mock import Mock, patch

from django.test import SimpleTestCase

from routing.edges import (
    avoid_edencom, avoid_triglavian, include_corptools_jumpbridges,
    include_eve_scout, include_titan_bridge,
)


class EdgeHelpersTest(SimpleTestCase):
    @patch("routing.edges.corptools_active", return_value=False)
    def test_include_corptools_jumpbridges_no_corptools(self, _mock_active: Mock) -> None:
        self.assertEqual(include_corptools_jumpbridges(), [])

    @patch("routing.edges.corptools_active", return_value=True)
    @patch("routing.edges.MapJumpBridge", create=True)
    def test_include_corptools_jumpbridges_with_data(self, mock_jumpbridge: Mock, _mock_active: Mock) -> None:
        mock_jumpbridge.objects.values_list.return_value.all.return_value = [(10, 20), (30, 40)]

        edges = include_corptools_jumpbridges(weight=2.5)

        self.assertEqual(
            edges,
            [
                (10, 20, {"p_shortest": 2.5, "p_safest": 2.5, "p_less_safe": 2.5, "type": "jump_bridge"}),
                (30, 40, {"p_shortest": 2.5, "p_safest": 2.5, "p_less_safe": 2.5, "type": "jump_bridge"}),
            ],
        )

    def test_include_eve_scout_returns_list(self) -> None:
        self.assertEqual(include_eve_scout("thera"), [])
        self.assertEqual(include_eve_scout("turnur"), [])

    def test_include_eve_scout_unknown_system_returns_empty_list(self) -> None:
        self.assertEqual(include_eve_scout("pochven"), [])

    def test_include_titan_bridge_current_stub(self) -> None:
        self.assertIsNone(include_titan_bridge(30000142, 5.0))


class AvoidanceEdgesTest(SimpleTestCase):
    @patch("routing.edges.SolarSystemConnection.objects.filter")
    @patch("routing.edges.TrigInvasion.objects.filter")
    def test_avoid_edencom(self, mock_filter: Mock, mock_connections: Mock) -> None:
        mock_filter.return_value.values_list.return_value.all.return_value = [30000142]
        mock_connections.return_value = [
            Mock(fromsolarsystem=30000001, tosolarsystem=30000142),
            Mock(fromsolarsystem=30000002, tosolarsystem=30000142),
        ]

        self.assertEqual(
            avoid_edencom(),
            [
                (30000001, 30000142, {"p_shortest": 50000.0, "p_safest": 50000.0, "p_less_safe": 50000.0}),
                (30000002, 30000142, {"p_shortest": 50000.0, "p_safest": 50000.0, "p_less_safe": 50000.0}),
            ],
        )

    @patch("routing.edges.SolarSystemConnection.objects.filter")
    @patch("routing.edges.TrigInvasion.objects.filter")
    def test_avoid_triglavian(self, mock_filter: Mock, mock_connections: Mock) -> None:
        mock_filter.return_value.values_list.return_value.all.return_value = [30000142]
        mock_connections.return_value = [
            Mock(fromsolarsystem=30000003, tosolarsystem=30000142),
        ]

        self.assertEqual(
            avoid_triglavian(),
            [
                (30000003, 30000142, {"p_shortest": 50000.0, "p_safest": 50000.0, "p_less_safe": 50000.0}),
            ],
        )


class EdgeWeightConsistencyTest(SimpleTestCase):
    """Test edge weight consistency and structure"""

    @patch("routing.edges.TrigInvasion.objects.filter")
    @patch("routing.edges.SolarSystemConnection.objects.filter")
    def test_avoidance_edges_have_high_weights(self, mock_conn: Mock, mock_inv: Mock) -> None:
        """Verify avoidance edges use high weights (50000.0)"""
        mock_inv.return_value.values_list.return_value.all.return_value = [1]
        mock_conn.return_value = [Mock(fromsolarsystem=9, tosolarsystem=1)]

        edges = avoid_edencom()
        self.assertEqual(edges[0][2], {"p_shortest": 50000.0, "p_safest": 50000.0, "p_less_safe": 50000.0})

    @patch("routing.edges.corptools_active", return_value=True)
    @patch("routing.edges.MapJumpBridge", create=True)
    def test_jumpbridge_edges_inherit_weight(self, mock_jumpbridge: Mock, _mock_active: Mock) -> None:
        """Verify jump bridge edges use specified weight"""
        mock_jumpbridge.objects.values_list.return_value.all.return_value = [(5, 6)]

        edges = include_corptools_jumpbridges(weight=3.0)
        self.assertEqual(edges, [(5, 6, {"p_shortest": 3.0, "p_safest": 3.0, "p_less_safe": 3.0, "type": "jump_bridge"})])


class EdgeEmptyResultsTest(SimpleTestCase):
    """Avoidance helpers return empty lists when no systems match"""

    @patch("routing.edges.SolarSystemConnection.objects.filter")
    @patch("routing.edges.TrigInvasion.objects.filter")
    def test_avoid_edencom_empty_when_no_occupied_systems(self, mock_trig_filter: Mock, _mock_conn_filter: Mock) -> None:
        mock_trig_filter.return_value.values_list.return_value.all.return_value = []

        self.assertEqual(avoid_edencom(), [])

    @patch("routing.edges.SolarSystemConnection.objects.filter")
    @patch("routing.edges.TrigInvasion.objects.filter")
    def test_avoid_triglavian_empty_when_no_occupied_systems(self, mock_trig_filter: Mock, _mock_conn_filter: Mock) -> None:
        mock_trig_filter.return_value.values_list.return_value.all.return_value = []

        self.assertEqual(avoid_triglavian(), [])

    @patch("routing.edges.corptools_active", return_value=True)
    @patch("routing.edges.MapJumpBridge", create=True)
    def test_include_corptools_jumpbridges_empty_when_no_bridges(self, mock_jumpbridge: Mock, _mock_active: Mock) -> None:
        """Corptools active but no bridges configured → empty list"""
        mock_jumpbridge.objects.values_list.return_value.all.return_value = []

        self.assertEqual(include_corptools_jumpbridges(), [])
