# Standard Library
from datetime import datetime, timedelta
from types import SimpleNamespace
from unittest.mock import Mock, patch

# Third Party
from discord import Embed

# Django
from django.test import SimpleTestCase

from incursions import helpers


class TestHelperFunctions(SimpleTestCase):
    def test_constellation_meta_returns_fallback_when_missing(self) -> None:
        with patch("incursions.helpers.logger.warning") as mock_warning:
            result = helpers._constellation_meta("Does Not Exist")

        self.assertEqual(
            result,
            {
                "Headquarter": "Unknown",
                "Assaults": [],
                "Vanguards": [],
            },
        )
        mock_warning.assert_called_once_with(
            "Constellation %s missing in static_data",
            "Does Not Exist",
        )

    def test_constellation_meta_returns_static_data_entry(self) -> None:
        expected = {
            "Headquarter": "Jita",
            "Assaults": ["A1"],
            "Vanguards": ["V1"],
        }

        with patch.dict("incursions.helpers.incursion_constellations", {"Alpha": expected}, clear=True):
            result = helpers._constellation_meta("Alpha")

        self.assertEqual(result, expected)

    def test_resolve_incursion_location_uses_fallback_lookups(self) -> None:
        incursion = Mock(constellation=None, staging_solar_system=None)
        fallback_constellation = SimpleNamespace(name="Fallback Constellation", region=None)
        fallback_region = SimpleNamespace(name="Fallback Region")
        fallback_system = SimpleNamespace(name="Fallback System", system_id=30000142)

        with (
            patch("incursions.helpers.Constellation.objects.get", return_value=fallback_constellation) as mock_constellation_get,
            patch("incursions.helpers.Region.objects.get", return_value=fallback_region) as mock_region_get,
            patch("incursions.helpers.SolarSystem.objects.get", return_value=fallback_system) as mock_system_get,
        ):
            constellation, region, staging = helpers._resolve_incursion_location(incursion)

        self.assertIs(constellation, fallback_constellation)
        self.assertIs(region, fallback_region)
        self.assertIs(staging, fallback_system)
        mock_constellation_get.assert_called_once_with(
            constellation_id=helpers.FALLBACK_CONSTELLATION_ID
        )
        mock_region_get.assert_called_once_with(system_id=helpers.FALLBACK_REGION_SYSTEM_ID)
        mock_system_get.assert_called_once_with(id=helpers.FALLBACK_SYSTEM_ID)

    def test_embed_established_addendum_high_sec_adds_mommy_time_and_route_flags(self) -> None:
        established_time = datetime(2026, 3, 25, 12, 0, 0)
        incursion = Mock(
            established_timestamp=established_time,
            is_high_sec=True,
            is_low_sec=False,
            security_string="High Sec",
        )

        constellation = SimpleNamespace(name="Constellation")
        region = SimpleNamespace(name="Region")
        staging = SimpleNamespace(name="HQ", system_id=30002510)
        focus_staging = SimpleNamespace(name="Old HQ", system_id=30000142)
        focus = SimpleNamespace(incursion=SimpleNamespace(staging_solar_system=focus_staging))

        with (
            patch("incursions.helpers._resolve_incursion_location", return_value=(constellation, region, staging)),
            patch("incursions.helpers.embed_base", return_value=Embed(title="base")),
            patch("incursions.helpers.route_length", return_value=7),
            patch("incursions.helpers.Focus.get_solo", return_value=focus),
            patch("incursions.helpers.route_check_triglavian", return_value=True),
            patch("incursions.helpers.route_check_edencom", return_value=False),
        ):
            embed = helpers.embed_established_addendum(incursion)

        fields = {field.name: str(field.value) for field in embed.fields}
        expected_mommy = int((established_time + timedelta(days=3)).timestamp())
        self.assertEqual(fields["Mommy Time"], f"<t:{expected_mommy}:R>")
        self.assertEqual(fields["Triglavian In Route"], "True")
        self.assertEqual(fields["Edencom In Route"], "False")

    def test_embed_mobilizing_includes_spawn_stats_when_timestamps_present(self) -> None:
        established_time = datetime(2026, 3, 20, 12, 0, 0)
        mobilizing_time = datetime(2026, 3, 22, 0, 0, 0)
        incursion = Mock(
            mobilizing_timestamp=mobilizing_time,
            established_timestamp=established_time,
            security_string="High Sec",
        )

        constellation = SimpleNamespace(name="Constellation")
        region = SimpleNamespace(name="Region")

        with (
            patch("incursions.helpers._resolve_incursion_location", return_value=(constellation, region, None)),
            patch("incursions.helpers.embed_base", return_value=Embed(title="base")),
        ):
            embed = helpers.embed_mobilizing(incursion)

        fields = {field.name: str(field.value) for field in embed.fields}
        self.assertIn("Max Spawn Stats", fields)
        self.assertIn("Uptime", fields["Max Spawn Stats"])
        self.assertIn("Unused", fields["Max Spawn Stats"])

    def test_embed_mobilizing_skips_spawn_stats_when_missing_timestamps(self) -> None:
        incursion = Mock(
            mobilizing_timestamp=None,
            established_timestamp=None,
            security_string="Low Sec",
        )

        constellation = SimpleNamespace(name="Constellation")
        region = SimpleNamespace(name="Region")

        with (
            patch("incursions.helpers._resolve_incursion_location", return_value=(constellation, region, None)),
            patch("incursions.helpers.embed_base", return_value=Embed(title="base")),
        ):
            embed = helpers.embed_mobilizing(incursion)

        field_names = [field.name for field in embed.fields]
        self.assertNotIn("Max Spawn Stats", field_names)

    def test_embed_waitlist_state_sets_open_and_closed_variants(self) -> None:
        with patch("incursions.helpers.get_site_url", return_value="https://example.com"):
            open_embed = helpers.embed_waitlist_state(waitlist=Mock(), is_open=True)
            closed_embed = helpers.embed_waitlist_state(waitlist=Mock(), is_open=False)

        self.assertEqual(open_embed.title, "Waitlist Open")
        self.assertEqual(open_embed.description, "Waitlist Open")
        self.assertEqual(open_embed.url, "https://example.com/incursions/waitlist/")

        self.assertEqual(closed_embed.title, "Waitlist Closed")
        self.assertEqual(closed_embed.description, "Waitlist Closed")
