"""Tests for config loading and parsing."""

from __future__ import annotations

import os
import tempfile
from pathlib import Path

import pytest

from pyfortis._types import LimitType, Severity
from pyfortis.config._raw_parser import raw_config_to_core
from pyfortis.config.loader import ConfigLoader
from pyfortis.errors import ConfigurationError


class TestConfigLoader:
    def test_load_yaml(self, tmp_path):
        config_file = tmp_path / "test.yaml"
        config_file.write_text(
            "meta:\n  version: '1.0'\nlimits:\n  - name: test\n    type: position\n"
        )
        result = ConfigLoader.load(config_file)
        assert result["meta"]["version"] == "1.0"

    def test_load_json(self, tmp_path):
        import json
        config_file = tmp_path / "test.json"
        config_file.write_text(json.dumps({"meta": {"version": "1.0"}, "limits": []}))
        result = ConfigLoader.load(config_file)
        assert result["meta"]["version"] == "1.0"

    def test_file_not_found(self):
        with pytest.raises(ConfigurationError, match="not found"):
            ConfigLoader.load("/nonexistent/path.yaml")

    def test_unsupported_format(self, tmp_path):
        config_file = tmp_path / "test.txt"
        config_file.write_text("hello")
        with pytest.raises(ConfigurationError, match="Unsupported"):
            ConfigLoader.load(config_file)

    def test_non_dict_top_level(self, tmp_path):
        config_file = tmp_path / "test.yaml"
        config_file.write_text("- item1\n- item2\n")
        with pytest.raises(ConfigurationError, match="mapping"):
            ConfigLoader.load(config_file)

    def test_env_var_substitution(self, tmp_path, monkeypatch):
        monkeypatch.setenv("TEST_VERSION", "2.0.0")
        config_file = tmp_path / "test.yaml"
        config_file.write_text("meta:\n  version: '${TEST_VERSION}'\n")
        result = ConfigLoader.load(config_file)
        assert result["meta"]["version"] == "2.0.0"

    def test_env_var_default(self, tmp_path, monkeypatch):
        monkeypatch.delenv("MISSING_VAR", raising=False)
        config_file = tmp_path / "test.yaml"
        config_file.write_text("meta:\n  version: '${MISSING_VAR:-1.0.0}'\n")
        result = ConfigLoader.load(config_file)
        assert result["meta"]["version"] == "1.0.0"

    def test_env_var_required_missing(self, tmp_path, monkeypatch):
        monkeypatch.delenv("REQUIRED_VAR", raising=False)
        config_file = tmp_path / "test.yaml"
        config_file.write_text("meta:\n  version: '${REQUIRED_VAR:?Must set REQUIRED_VAR}'\n")
        with pytest.raises(ConfigurationError, match="Must set REQUIRED_VAR"):
            ConfigLoader.load(config_file)

    def test_load_string_yaml(self):
        result = ConfigLoader.load_string("meta:\n  version: '1.0'\n")
        assert result["meta"]["version"] == "1.0"

    def test_load_string_json(self):
        result = ConfigLoader.load_string('{"meta": {"version": "1.0"}}', fmt="json")
        assert result["meta"]["version"] == "1.0"


class TestRawParser:
    def test_basic_parse(self, sample_config):
        limits, metrics, cbs, esc, meta = raw_config_to_core(sample_config)
        assert len(limits) == 2
        assert len(metrics) == 1
        assert len(cbs) == 1
        assert meta["version"] == "1.0.0"

    def test_limit_types(self, sample_config):
        limits, *_ = raw_config_to_core(sample_config)
        assert limits[0].type is LimitType.POSITION
        assert limits[1].type is LimitType.CONCENTRATION

    def test_escalation_policy(self, sample_config):
        *_, esc, _ = raw_config_to_core(sample_config)
        assert Severity.WARNING in esc.escalation
        assert Severity.CRITICAL in esc.escalation

    def test_invalid_limit_type(self):
        config = {
            "limits": [{"name": "bad", "type": "nonexistent"}],
        }
        with pytest.raises(ConfigurationError, match="Invalid limit"):
            raw_config_to_core(config)

    def test_empty_config(self):
        limits, metrics, cbs, esc, meta = raw_config_to_core({})
        assert limits == []
        assert metrics == []
        assert cbs == []
        assert meta == {}
