import json
import os
import tempfile

from companion.config import load_config


def test_load_config_reads_json_and_expands_tilde():
    with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
        json.dump(
            {
                "companion": {
                    "name": "SAN",
                    "persona": {
                        "role": "companion",
                        "tone": "reflective",
                        "style": "questioning",
                        "boundaries": [],
                    },
                    "memory": {
                        "session_turns": 20,
                        "persistent_store": "~/mem.db",
                        "summarize_after": 10,
                    },
                    "chat": {
                        "streaming": True,
                        "max_response_tokens": 2048,
                        "default_temperature": 0.7,
                        "allow_temperature_override": True,
                    },
                },
                "vault": {
                    "path": "~/test-vault",
                    "indexing": {
                        "auto_sync": False,
                        "auto_sync_interval_minutes": 1440,
                        "watch_fs_events": False,
                        "file_patterns": ["*.md"],
                        "deny_dirs": [".git"],
                        "deny_patterns": [".*"],
                    },
                    "chunking_rules": {},
                },
                "rag": {
                    "embedding": {
                        "provider": "ollama",
                        "model": "dummy",
                        "base_url": "http://localhost:11434",
                        "dimensions": 4,
                        "batch_size": 2,
                    },
                    "vector_store": {
                        "type": "lancedb",
                        "path": "~/.companion/vectors.lance",
                    },
                    "search": {
                        "default_top_k": 8,
                        "max_top_k": 20,
                        "similarity_threshold": 0.75,
                        "hybrid_search": {
                            "enabled": False,
                            "keyword_weight": 0.3,
                            "semantic_weight": 0.7,
                        },
                        "filters": {
                            "date_range_enabled": True,
                            "tag_filter_enabled": True,
                            "directory_filter_enabled": True,
                        },
                    },
                },
                "model": {
                    "inference": {
                        "backend": "llama.cpp",
                        "model_path": "",
                        "context_length": 8192,
                        "gpu_layers": 35,
                        "batch_size": 512,
                        "threads": 8,
                    },
                    "fine_tuning": {
                        "base_model": "",
                        "output_dir": "",
                        "lora_rank": 16,
                        "lora_alpha": 32,
                        "learning_rate": 0.0002,
                        "batch_size": 4,
                        "gradient_accumulation_steps": 4,
                        "num_epochs": 3,
                        "warmup_steps": 100,
                        "save_steps": 500,
                        "eval_steps": 250,
                        "training_data_path": "",
                        "validation_split": 0.1,
                    },
                    "retrain_schedule": {
                        "auto_reminder": True,
                        "default_interval_days": 90,
                        "reminder_channels": [],
                    },
                },
                "api": {
                    "host": "127.0.0.1",
                    "port": 7373,
                    "cors_origins": [],
                    "auth": {"enabled": False},
                },
                "ui": {
                    "web": {
                        "enabled": True,
                        "theme": "obsidian",
                        "features": {
                            "streaming": True,
                            "citations": True,
                            "source_preview": True,
                        },
                    },
                    "cli": {"enabled": True, "rich_output": True},
                },
                "logging": {
                    "level": "INFO",
                    "file": "",
                    "max_size_mb": 100,
                    "backup_count": 5,
                },
                "security": {
                    "local_only": True,
                    "vault_path_traversal_check": True,
                    "sensitive_content_detection": True,
                    "sensitive_patterns": [],
                    "require_confirmation_for_external_apis": True,
                },
            },
            f,
        )
        path = f.name
    try:
        config = load_config(path)
        assert config.vault.path == os.path.expanduser("~/test-vault")
        assert config.rag.vector_store.path == os.path.expanduser(
            "~/.companion/vectors.lance"
        )
        assert config.companion.memory.persistent_store == os.path.expanduser(
            "~/mem.db"
        )
    finally:
        os.unlink(path)


def test_tilde_expansion_in_list_values():
    """Test that tilde expansion works for list values."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
        json.dump(
            {
                "companion": {
                    "name": "SAN",
                    "persona": {
                        "role": "companion",
                        "tone": "reflective",
                        "style": "questioning",
                        "boundaries": [],
                    },
                    "memory": {
                        "session_turns": 20,
                        "persistent_store": "~/mem.db",
                        "summarize_after": 10,
                    },
                    "chat": {
                        "streaming": True,
                        "max_response_tokens": 2048,
                        "default_temperature": 0.7,
                        "allow_temperature_override": True,
                    },
                },
                "vault": {
                    "path": "~/test-vault",
                    "indexing": {
                        "auto_sync": False,
                        "auto_sync_interval_minutes": 1440,
                        "watch_fs_events": False,
                        "file_patterns": ["*.md"],
                        "deny_dirs": ["~/secret", ".git"],
                        "deny_patterns": [".*"],
                    },
                    "chunking_rules": {},
                },
                "rag": {
                    "embedding": {
                        "provider": "ollama",
                        "model": "dummy",
                        "base_url": "http://localhost:11434",
                        "dimensions": 4,
                        "batch_size": 2,
                    },
                    "vector_store": {
                        "type": "lancedb",
                        "path": "~/.companion/vectors.lance",
                    },
                    "search": {
                        "default_top_k": 8,
                        "max_top_k": 20,
                        "similarity_threshold": 0.75,
                        "hybrid_search": {
                            "enabled": False,
                            "keyword_weight": 0.3,
                            "semantic_weight": 0.7,
                        },
                        "filters": {
                            "date_range_enabled": True,
                            "tag_filter_enabled": True,
                            "directory_filter_enabled": True,
                        },
                    },
                },
                "model": {
                    "inference": {
                        "backend": "llama.cpp",
                        "model_path": "",
                        "context_length": 8192,
                        "gpu_layers": 35,
                        "batch_size": 512,
                        "threads": 8,
                    },
                    "fine_tuning": {
                        "base_model": "",
                        "output_dir": "",
                        "lora_rank": 16,
                        "lora_alpha": 32,
                        "learning_rate": 0.0002,
                        "batch_size": 4,
                        "gradient_accumulation_steps": 4,
                        "num_epochs": 3,
                        "warmup_steps": 100,
                        "save_steps": 500,
                        "eval_steps": 250,
                        "training_data_path": "",
                        "validation_split": 0.1,
                    },
                    "retrain_schedule": {
                        "auto_reminder": True,
                        "default_interval_days": 90,
                        "reminder_channels": [],
                    },
                },
                "api": {
                    "host": "127.0.0.1",
                    "port": 7373,
                    "cors_origins": [],
                    "auth": {"enabled": False},
                },
                "ui": {
                    "web": {
                        "enabled": True,
                        "theme": "obsidian",
                        "features": {
                            "streaming": True,
                            "citations": True,
                            "source_preview": True,
                        },
                    },
                    "cli": {"enabled": True, "rich_output": True},
                },
                "logging": {
                    "level": "INFO",
                    "file": "",
                    "max_size_mb": 100,
                    "backup_count": 5,
                },
                "security": {
                    "local_only": True,
                    "vault_path_traversal_check": True,
                    "sensitive_content_detection": True,
                    "sensitive_patterns": [],
                    "require_confirmation_for_external_apis": True,
                },
            },
            f,
        )
        path = f.name
    try:
        config = load_config(path)
        # Check tilde expansion in list values
        assert config.vault.indexing.deny_dirs[0] == os.path.expanduser("~/secret")
    finally:
        os.unlink(path)


def test_load_config_missing_file():
    """Test that loading a missing file raises FileNotFoundError."""
    with tempfile.TemporaryDirectory() as tmp:
        missing_path = os.path.join(tmp, "nonexistent.json")
        try:
            load_config(missing_path)
            assert False, "Should have raised an exception"
        except FileNotFoundError:
            pass  # Expected


def test_load_config_malformed_json():
    """Test that malformed JSON raises JSONDecodeError."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
        f.write("{invalid json")
        path = f.name
    try:
        load_config(path)
        assert False, "Should have raised an exception"
    except json.JSONDecodeError:
        pass  # Expected
    finally:
        os.unlink(path)


def test_load_config_missing_required_field():
    """Test that missing required field raises ValidationError."""
    with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as f:
        # Missing required fields like "companion"
        json.dump({"vault": {"path": "~/test"}}, f)
        path = f.name
    try:
        load_config(path)
        assert False, "Should have raised an exception"
    except Exception as e:
        # Should be a Pydantic validation error
        assert "companion" in str(e).lower() or "validation" in str(e).lower()
    finally:
        os.unlink(path)
