"""Tests for TOML config loading, precedence, and masking."""

from __future__ import annotations

import json
from pathlib import Path
from unittest.mock import patch

import pytest

from certisigma_census.config import (
    _deep_merge,
    _find_project_config,
    config_paths,
    init_config,
    load_config,
    mask_sensitive,
)


class TestDeepMerge:
    def test_flat_merge(self):
        result = _deep_merge({"a": 1, "b": 2}, {"b": 3, "c": 4})
        assert result == {"a": 1, "b": 3, "c": 4}

    def test_nested_merge(self):
        base = {"scan": {"include": [], "max_size": "1G"}}
        overlay = {"scan": {"include": ["*.pdf"]}}
        result = _deep_merge(base, overlay)
        assert result["scan"]["include"] == ["*.pdf"]
        assert result["scan"]["max_size"] == "1G"

    def test_does_not_mutate_base(self):
        base = {"a": {"b": 1}}
        overlay = {"a": {"b": 2}}
        _deep_merge(base, overlay)
        assert base["a"]["b"] == 1


class TestMaskSensitive:
    def test_masks_api_key(self):
        cfg = {"api_key": "cs_abcdefghij1234567890"}
        masked = mask_sensitive(cfg)
        assert masked["api_key"] == "cs_a...7890"

    def test_short_key_masked_fully(self):
        cfg = {"api_key": "short"}
        masked = mask_sensitive(cfg)
        assert masked["api_key"] == "****"

    def test_empty_key_not_masked(self):
        cfg = {"api_key": ""}
        masked = mask_sensitive(cfg)
        assert masked["api_key"] == ""

    def test_non_sensitive_preserved(self):
        cfg = {"base_url": "https://api.certisigma.ch", "source": "test"}
        masked = mask_sensitive(cfg)
        assert masked["base_url"] == "https://api.certisigma.ch"

    def test_nested_masking(self):
        cfg = {"scan": {"include": ["*.pdf"]}}
        masked = mask_sensitive(cfg)
        assert masked["scan"]["include"] == ["*.pdf"]


class TestFindProjectConfig:
    def test_finds_config_in_current_dir(self, tmp_path):
        config_file = tmp_path / ".census.toml"
        config_file.write_text('api_key = "test"')
        result = _find_project_config(tmp_path)
        assert result == config_file

    def test_finds_config_in_parent(self, tmp_path):
        config_file = tmp_path / ".census.toml"
        config_file.write_text('api_key = "test"')
        child = tmp_path / "sub" / "dir"
        child.mkdir(parents=True)
        result = _find_project_config(child)
        assert result == config_file

    def test_returns_none_when_not_found(self, tmp_path):
        result = _find_project_config(tmp_path)
        assert result is None


class TestLoadConfig:
    def test_returns_defaults_when_no_files(self, tmp_path):
        cfg = load_config(project_dir=tmp_path, skip_user=True)
        assert cfg["api_key"] == ""
        assert cfg["base_url"] == "https://api.certisigma.ch"

    def test_project_config_overrides_defaults(self, tmp_path):
        config_file = tmp_path / ".census.toml"
        config_file.write_text('source = "my-project"\n')
        with patch("certisigma_census.config._find_project_config", return_value=config_file):
            cfg = load_config(skip_user=True)
        assert cfg["source"] == "my-project"

    def test_user_config_loaded(self, tmp_path):
        user_config = tmp_path / "config.toml"
        user_config.write_text('base_url = "https://custom.api.ch"\n')
        with patch("certisigma_census.config._user_config_path", return_value=user_config):
            cfg = load_config(skip_project=True)
        assert cfg["base_url"] == "https://custom.api.ch"

    def test_project_overrides_user(self, tmp_path):
        user_config = tmp_path / "user.toml"
        user_config.write_text('source = "user-source"\n')
        project_config = tmp_path / ".census.toml"
        project_config.write_text('source = "project-source"\n')
        with patch("certisigma_census.config._user_config_path", return_value=user_config), \
             patch("certisigma_census.config._find_project_config", return_value=project_config):
            cfg = load_config()
        assert cfg["source"] == "project-source"


class TestInitConfig:
    def test_creates_template(self, tmp_path):
        path = tmp_path / "sub" / "config.toml"
        init_config(path)
        assert path.exists()
        content = path.read_text()
        assert "CertiSigma Census" in content
        assert "api_key" in content

    def test_creates_parent_dirs(self, tmp_path):
        path = tmp_path / "deep" / "nested" / "config.toml"
        init_config(path)
        assert path.exists()


class TestLoadConfigIsolation:
    def test_returned_config_does_not_share_references_with_defaults(self, tmp_path):
        """load_config() must return an independent copy — no aliasing of nested dicts."""
        from certisigma_census.config import _DEFAULT_CONFIG

        cfg = load_config(project_dir=tmp_path, skip_user=True)
        cfg["scan"]["include"].append("*.log")
        assert _DEFAULT_CONFIG["scan"]["include"] == []


class TestConfigPaths:
    def test_returns_user_and_project(self):
        paths = config_paths()
        assert "user" in paths
        assert "project" in paths
