"""Tests for the config module."""

import unittest
from unittest.mock import MagicMock, mock_open, patch

from video_thumbnail_creator.config import (
    ALLOWED_KEYS,
    get_effective_config,
    get_value,
    list_config,
    set_value,
    _BUILTIN_DEFAULTS,
)


class TestAllowedKeys(unittest.TestCase):
    def test_all_expected_keys_present(self):
        expected = {
            "claude.api_key",
            "claude.model",
            "tools.ffmpeg",
            "tools.ffprobe",
            "defaults.output_name_suffix",
            "defaults.mode",
            "defaults.format",
            "defaults.embedded_image",
            "badges.enabled",
        }
        self.assertEqual(set(ALLOWED_KEYS), expected)


class TestGetEffectiveConfig(unittest.TestCase):
    def test_returns_defaults_when_no_file(self):
        with patch("video_thumbnail_creator.config.load_config", return_value={}):
            result = get_effective_config()
        self.assertEqual(result["tools"]["ffmpeg"], "ffmpeg")
        self.assertEqual(result["tools"]["ffprobe"], "ffprobe")
        self.assertEqual(result["defaults"]["output_name_suffix"], "-poster")
        self.assertEqual(result["defaults"]["mode"], "manual")
        self.assertEqual(result["defaults"]["format"], "poster")
        self.assertEqual(result["claude"]["model"], "claude-opus-4-5")

    def test_file_values_override_defaults(self):
        file_cfg = {"claude": {"model": "claude-3-opus"}, "tools": {"ffmpeg": "/usr/local/bin/ffmpeg"}}
        with patch("video_thumbnail_creator.config.load_config", return_value=file_cfg):
            result = get_effective_config()
        self.assertEqual(result["claude"]["model"], "claude-3-opus")
        self.assertEqual(result["tools"]["ffmpeg"], "/usr/local/bin/ffmpeg")
        # Unset file value still comes from defaults
        self.assertEqual(result["tools"]["ffprobe"], "ffprobe")

    def test_does_not_mutate_builtin_defaults(self):
        original_model = _BUILTIN_DEFAULTS["claude"]["model"]
        with patch("video_thumbnail_creator.config.load_config", return_value={"claude": {"model": "other"}}):
            get_effective_config()
        self.assertEqual(_BUILTIN_DEFAULTS["claude"]["model"], original_model)


class TestGetValue(unittest.TestCase):
    def test_returns_value_when_set(self):
        with patch("video_thumbnail_creator.config.load_config", return_value={"claude": {"api_key": "sk-test"}}):
            self.assertEqual(get_value("claude.api_key"), "sk-test")

    def test_returns_none_when_not_set(self):
        with patch("video_thumbnail_creator.config.load_config", return_value={}):
            self.assertIsNone(get_value("claude.api_key"))

    def test_raises_on_unknown_key(self):
        with self.assertRaises(ValueError) as ctx:
            get_value("unknown.key")
        self.assertIn("unknown.key", str(ctx.exception))


class TestSetValue(unittest.TestCase):
    def test_raises_on_unknown_key(self):
        with self.assertRaises(ValueError):
            set_value("bad.key", "value")

    def test_calls_save_with_updated_value(self):
        existing = {"claude": {"model": "old-model"}}
        with patch("video_thumbnail_creator.config.load_config", return_value=existing), \
             patch("video_thumbnail_creator.config.save_config") as mock_save:
            set_value("claude.model", "new-model")
        mock_save.assert_called_once()
        saved = mock_save.call_args[0][0]
        self.assertEqual(saved["claude"]["model"], "new-model")

    def test_preserves_existing_values(self):
        existing = {"claude": {"model": "old", "api_key": "key123"}}
        with patch("video_thumbnail_creator.config.load_config", return_value=existing), \
             patch("video_thumbnail_creator.config.save_config") as mock_save:
            set_value("claude.model", "new")
        saved = mock_save.call_args[0][0]
        self.assertEqual(saved["claude"]["api_key"], "key123")


class TestListConfig(unittest.TestCase):
    def test_returns_file_config(self):
        file_cfg = {"tools": {"ffmpeg": "/custom/ffmpeg"}}
        with patch("video_thumbnail_creator.config.load_config", return_value=file_cfg):
            result = list_config()
        self.assertEqual(result, file_cfg)

    def test_returns_empty_when_no_config(self):
        with patch("video_thumbnail_creator.config.load_config", return_value={}):
            result = list_config()
        self.assertEqual(result, {})


class TestResolveOutputPath(unittest.TestCase):
    """Test the output path resolution using suffix logic."""

    def test_suffix_appended_to_video_stem(self):
        from video_thumbnail_creator.cli import _resolve_output_path
        import tempfile
        import os

        with tempfile.TemporaryDirectory() as tmpdir:
            result = _resolve_output_path(
                os.path.join(tmpdir, "2025-05-15_Starship_IFT7.mkv"),
                tmpdir,
                "-poster",
            )
        self.assertTrue(result.endswith("2025-05-15_Starship_IFT7-poster.jpg"))

    def test_empty_suffix_uses_stem_only(self):
        from video_thumbnail_creator.cli import _resolve_output_path
        import tempfile
        import os

        with tempfile.TemporaryDirectory() as tmpdir:
            result = _resolve_output_path(
                os.path.join(tmpdir, "video.mp4"),
                tmpdir,
                "",
            )
        self.assertTrue(result.endswith("video.jpg"))


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