"""Tests for core.services.umc_service.update_umc_options."""

import sys
import tempfile
import unittest
from pathlib import Path

PROJECT_ROOT = Path(__file__).resolve().parent.parent
if str(PROJECT_ROOT) not in sys.path:
    sys.path.insert(0, str(PROJECT_ROOT))

from core import constants
from core.exceptions import ValidationError
from core.io.umc_parser import parse_umc_file
from core.io.umc_writer import write
from core.services import umc_service


class TestUpdateUmcOptions(unittest.TestCase):
    def setUp(self) -> None:
        self.sandbox = tempfile.TemporaryDirectory()
        self.sandbox_path = Path(self.sandbox.name)
        constants.UMC_MASTER_FILE = self.sandbox_path / "umc_mapcycle_master.txt"
        constants.UMC_FILE = self.sandbox_path / "cstrike" / "umc_mapcycle.txt"
        constants.UMC_FILE.parent.mkdir(parents=True, exist_ok=True)
        constants.CONFIG_FILE = self.sandbox_path / "config.json"
        constants.CONFIG_FILE.write_text('{"load_order": []}', encoding="utf-8")
        constants.REPOSITORY = self.sandbox_path / "repository"
        constants.REPOSITORY.mkdir(parents=True, exist_ok=True)

        write(
            constants.UMC_MASTER_FILE,
            {"Normal": {"options": {"maps_invote": "5"}, "maps": {"de_dust2": {"tier": "1"}}}},
            create_backup=False,
        )

    def tearDown(self) -> None:
        self.sandbox.cleanup()

    def test_rejects_payload_without_categories_key(self) -> None:
        with self.assertRaises(ValueError):
            umc_service.update_umc_options({})

    def test_rejects_non_dict_payload(self) -> None:
        with self.assertRaises(ValueError):
            umc_service.update_umc_options("not a dict")

    def test_default_destination_targets_the_master_file(self) -> None:
        """Regression test: `update_umc_options` must default to writing the
        MASTER file (source of truth), not the server-generated UMC_FILE --
        the two used to be confusingly aliased under the same local name.
        """
        payload = {"categories": {"Normal": {"options": {}, "maps": {}}}}

        umc_service.update_umc_options(payload)

        master_content = constants.UMC_MASTER_FILE.read_text(encoding="utf-8")
        self.assertIn("Normal", master_content)

    def test_updates_known_category_option(self) -> None:
        payload = {"categories": {"Normal": {"options": {"maps_invote": "8"}, "maps": {}}}}

        umc_service.update_umc_options(payload)

        result = parse_umc_file(constants.UMC_MASTER_FILE)
        self.assertEqual(result["Normal"]["options"].get("maps_invote"), "8")

    def test_ignores_unknown_category(self) -> None:
        payload = {"categories": {"DoesNotExist": {"options": {}, "maps": {}}}}

        umc_service.update_umc_options(payload)

        result = parse_umc_file(constants.UMC_MASTER_FILE)
        self.assertNotIn("DoesNotExist", result)

    def test_ignores_unknown_map(self) -> None:
        payload = {
            "categories": {"Normal": {"options": {}, "maps": {"de_never_existed": {"tier": "1"}}}}
        }

        umc_service.update_umc_options(payload)

        result = parse_umc_file(constants.UMC_MASTER_FILE)
        self.assertNotIn("de_never_existed", result["Normal"]["maps"])

    def test_filters_out_invalid_option_but_keeps_valid_ones(self) -> None:
        payload = {
            "categories": {
                "Normal": {"options": {}, "maps": {"de_dust2": {"tier": "1", "banana": "42"}}}
            }
        }

        with self.assertRaises(ValidationError):
            umc_service.update_umc_options(payload)

        result = parse_umc_file(constants.UMC_MASTER_FILE)
        map_options = result["Normal"]["maps"]["de_dust2"]
        self.assertEqual(map_options.get("tier"), "1")
        self.assertNotIn("banana", map_options)

    def test_removes_maps_absent_from_payload(self) -> None:
        """update_umc_options replaces the category content wholesale, so a map
        omitted from the payload is dropped, not merely left untouched.
        """
        payload = {"categories": {"Normal": {"options": {}, "maps": {}}}}

        umc_service.update_umc_options(payload)

        result = parse_umc_file(constants.UMC_MASTER_FILE)
        self.assertEqual(result["Normal"]["maps"], {})


if __name__ == "__main__":
    unittest.main()
