#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Location: ./tests/fuzz/fuzzers/fuzz_config_parser.py
Copyright 2026
SPDX-License-Identifier: Apache-2.0
Authors: Mihai Criveti

Coverage-guided fuzzing for configuration parsing using Atheris.
"""

# Standard
import os
import sys
import tempfile

# Third-Party
import atheris

# Ensure the project is in the path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "../../.."))

try:
    # Third-Party
    from pydantic import ValidationError

    # First-Party
    from mcpgateway.config import Settings
except ImportError as e:
    print(f"Import error: {e}")
    sys.exit(1)


def TestOneInput(data: bytes) -> None:  # noqa: N802
    """Fuzz target for configuration parsing.

    Args:
        data: Raw bytes from Atheris fuzzer
    """
    fdp = atheris.FuzzedDataProvider(data)

    try:
        if fdp.remaining_bytes() < 1:
            return

        choice = fdp.ConsumeIntInRange(0, 3)

        if choice == 0:
            # Test Settings creation with random kwargs
            kwargs = {}

            # Basic string fields
            string_fields = ["app_name", "host", "database_url", "basic_auth_user", "basic_auth_password", "log_level", "transport_type"]

            for field in string_fields:
                if fdp.ConsumeBool():
                    kwargs[field] = fdp.ConsumeUnicodeNoSurrogates(100)

            # Integer fields
            int_fields = ["port", "resource_cache_size", "resource_cache_ttl", "tool_timeout"]
            for field in int_fields:
                if fdp.ConsumeBool():
                    kwargs[field] = fdp.ConsumeIntInRange(-1000, 65535)

            # Boolean fields
            bool_fields = ["skip_ssl_verify", "auth_required", "docs_allow_basic_auth"]
            for field in bool_fields:
                if fdp.ConsumeBool():
                    kwargs[field] = fdp.ConsumeBool()

            settings = Settings(**kwargs)

            # Test methods that might fail
            try:
                settings.validate_transport()
            except ValueError:
                # Expected for invalid transport types
                pass

            try:
                settings.validate_database()
            except (ValueError, OSError):
                # Expected for invalid database URLs
                pass

            # Test properties
            _ = settings.api_key
            _ = settings.database_settings

        elif choice == 1:
            # Test environment variable parsing
            env_vars = {}

            # Generate random environment variables
            for _ in range(fdp.ConsumeIntInRange(0, 10)):
                key = fdp.ConsumeUnicodeNoSurrogates(30)
                value = fdp.ConsumeUnicodeNoSurrogates(100)
                if key and not key.startswith("_"):
                    env_vars[key] = value

            # Backup original env
            original_env = dict(os.environ)

            try:
                # Set test environment
                os.environ.update(env_vars)

                # Create settings (will read from env)
                settings = Settings()

                # Test basic functionality
                _ = settings.model_dump()

            finally:
                # Restore original environment
                os.environ.clear()
                os.environ.update(original_env)

        elif choice == 2:
            # Test with .env file content
            env_content = ""
            for _ in range(fdp.ConsumeIntInRange(0, 20)):
                key = fdp.ConsumeUnicodeNoSurrogates(30)
                value = fdp.ConsumeUnicodeNoSurrogates(100)
                if key and "=" not in key and "\n" not in key:
                    env_content += f"{key}={value}\n"

            # Create temporary .env file
            with tempfile.NamedTemporaryFile(mode="w", suffix=".env", delete=False) as f:
                f.write(env_content)
                env_file_path = f.name

            try:
                # Test loading from .env file (simulate)
                lines = env_content.split("\n")
                env_dict = {}
                for line in lines:
                    if "=" in line and not line.startswith("#"):
                        key, value = line.split("=", 1)
                        env_dict[key.strip()] = value.strip()

                # Test with parsed values
                if env_dict:
                    settings = Settings(**env_dict)
                    _ = settings.model_dump()

            finally:
                # Clean up temp file
                try:
                    os.unlink(env_file_path)
                except OSError:
                    pass

        else:
            # Test database URL parsing
            db_url = fdp.ConsumeUnicodeNoSurrogates(200)

            try:
                settings = Settings(database_url=db_url)
                db_settings = settings.database_settings

                # Verify basic structure if parsing succeeded
                if isinstance(db_settings, dict):
                    # Should have basic keys for valid URLs
                    pass

            except (ValueError, ValidationError):
                # Expected for invalid URLs
                pass

    except (ValidationError, ValueError, TypeError, OSError, KeyError):
        # Expected exceptions for invalid configuration
        pass
    except Exception:
        # Unexpected exceptions should be caught by Atheris
        raise


def main():
    """Main fuzzing entry point."""
    # Instrument all Python code for coverage guidance
    atheris.instrument_all()

    # Setup fuzzing with command line arguments
    atheris.Setup(sys.argv, TestOneInput)

    # Start fuzzing
    atheris.Fuzz()


if __name__ == "__main__":
    main()
