"""End-to-end tests that exercise the real ``load_and_validate_config_file``
through a temp YAML file. Anything that breaks here would break the actual
``prowler aws -c …`` code path."""

import logging
import os
import pathlib
from typing import Callable

import pytest

from prowler.config.config import load_and_validate_config_file


@pytest.fixture
def write_config(tmp_path: pathlib.Path) -> Callable[[str], str]:
    def _write(content: str) -> str:
        path = tmp_path / "config.yaml"
        path.write_text(content)
        return str(path)

    return _write


class Test_Loader_With_Schema_Integration:
    def test_shipped_default_config_loads_without_warnings(self, caplog):
        """The default ``prowler/config/config.yaml`` must round-trip every
        provider WITHOUT emitting any schema warnings. If this fails,
        someone added a key to the YAML without updating the schema."""
        repo_root = pathlib.Path(os.path.dirname(os.path.realpath(__file__))).parents[2]
        shipped = repo_root / "prowler" / "config" / "config.yaml"
        with caplog.at_level(logging.WARNING, logger="prowler"):
            for provider in [
                "aws",
                "azure",
                "gcp",
                "kubernetes",
                "m365",
                "github",
                "mongodbatlas",
                "cloudflare",
                "vercel",
            ]:
                cfg = load_and_validate_config_file(provider, str(shipped))
                # Provider always exists in the shipped file → non-empty.
                assert cfg, f"{provider} returned an empty config"

        offending = [
            r.getMessage()
            for r in caplog.records
            if "prowler.config[" in r.getMessage()
        ]
        assert not offending, (
            "Shipped config.yaml triggered schema warnings — schema or YAML out of sync:\n"
            + "\n".join(offending)
        )

    def test_user_config_with_bad_threshold_falls_back(self, write_config, caplog):
        path = write_config(
            "aws:\n"
            "  threat_detection_privilege_escalation_threshold: 5.0\n"
            "  lambda_min_azs: 2\n"
        )
        with caplog.at_level(logging.WARNING, logger="prowler"):
            cfg = load_and_validate_config_file("aws", path)
        assert cfg == {"lambda_min_azs": 2}
        assert any(
            "threat_detection_privilege_escalation_threshold" in r.getMessage()
            for r in caplog.records
        )

    def test_old_format_config_still_works(self, write_config):
        # Old format = flat keys, no provider header.
        path = write_config(
            "max_ec2_instance_age_in_days: 90\n"
            "ecr_repository_vulnerability_minimum_severity: HIGH\n"
        )
        cfg = load_and_validate_config_file("aws", path)
        assert cfg == {
            "max_ec2_instance_age_in_days": 90,
            "ecr_repository_vulnerability_minimum_severity": "HIGH",
        }

    def test_unknown_keys_pass_through_via_loader(self, write_config):
        path = write_config(
            "aws:\n" "  third_party_plugin_setting: hello\n" "  lambda_min_azs: 2\n"
        )
        cfg = load_and_validate_config_file("aws", path)
        assert cfg == {
            "third_party_plugin_setting": "hello",
            "lambda_min_azs": 2,
        }

    def test_quoted_numeric_is_coerced_via_loader(self, write_config):
        # YAML quotes the number: ``"180"`` arrives as a Python str.
        # The schema must coerce it to int so downstream comparisons work.
        path = write_config('aws:\n  max_ec2_instance_age_in_days: "180"\n')
        cfg = load_and_validate_config_file("aws", path)
        assert cfg == {"max_ec2_instance_age_in_days": 180}
        assert isinstance(cfg["max_ec2_instance_age_in_days"], int)

    def test_invalid_yaml_shape_list_as_string_drops_key(self, write_config, caplog):
        path = write_config(
            "aws:\n"
            "  disallowed_regions: me-south-1\n"  # forgot list dashes
            "  lambda_min_azs: 2\n"
        )
        with caplog.at_level(logging.WARNING, logger="prowler"):
            cfg = load_and_validate_config_file("aws", path)
        assert cfg == {"lambda_min_azs": 2}
        assert any("disallowed_regions" in r.getMessage() for r in caplog.records)

    def test_other_providers_unaffected_by_aws_block(self, write_config):
        path = write_config(
            "aws:\n  max_ec2_instance_age_in_days: 90\n" "gcp:\n  mig_min_zones: 5\n"
        )
        assert load_and_validate_config_file("aws", path) == {
            "max_ec2_instance_age_in_days": 90
        }
        assert load_and_validate_config_file("gcp", path) == {"mig_min_zones": 5}

    def test_missing_provider_block_returns_empty(self, write_config):
        path = write_config("aws:\n  max_ec2_instance_age_in_days: 90\n")
        assert load_and_validate_config_file("azure", path) == {}
