# Module: Configuration Validator
# Purpose: Validates configuration structure, paths, data types, semantic rules, and file existence.
# Dependencies: loader_core for get-config-value

# Configuration Validation Functions
# Validates configuration structure, paths, data types, semantic rules, and files

# Validate configuration structure - checks required sections exist
export def validate-config-structure [
    config: record
] {
    let required_sections = ["core", "paths", "debug", "sops"]
    mut errors = []
    mut warnings = []

    for section in $required_sections {
        let section_value = ($config | get -o $section | default null)
        if ($section_value | is-empty) {
            $errors = ($errors | append {
                type: "missing_section",
                severity: "error",
                section: $section,
                message: $"Missing required configuration section: ($section)"
            })
        }
    }

    {
        valid: (($errors | length) == 0),
        errors: $errors,
        warnings: $warnings
    }
}

# Validate path values - checks paths exist and are absolute
export def validate-path-values [
    config: record
] {
    let required_paths = ["base", "providers", "taskservs", "clusters"]
    mut errors = []
    mut warnings = []

    let paths = ($config | get -o paths | default {})

    for path_name in $required_paths {
        let path_value = ($paths | get -o $path_name | default null)

        if ($path_value | is-empty) {
            $errors = ($errors | append {
                type: "missing_path",
                severity: "error",
                path: $path_name,
                message: $"Missing required path: paths.($path_name)"
            })
        } else {
            # Check if path is absolute
            if not ($path_value | str starts-with "/") {
                $warnings = ($warnings | append {
                    type: "relative_path",
                    severity: "warning",
                    path: $path_name,
                    value: $path_value,
                    message: $"Path paths.($path_name) should be absolute, got: ($path_value)"
                })
            }

            # Check if base path exists (critical for system operation)
            if $path_name == "base" {
                if not ($path_value | path exists) {
                    $errors = ($errors | append {
                        type: "path_not_exists",
                        severity: "error",
                        path: $path_name,
                        value: $path_value,
                        message: $"Base path does not exist: ($path_value)"
                    })
                }
            }
        }
    }

    {
        valid: (($errors | length) == 0),
        errors: $errors,
        warnings: $warnings
    }
}

# Validate data types - checks configuration values have correct types
export def validate-data-types [
    config: record
] {
    mut errors = []
    mut warnings = []

    # Validate core.version follows semantic versioning pattern
    let core_version = ($config | get -o core.version | default null)
    if ($core_version | is-not-empty) {
        let version_pattern = "^\\d+\\.\\d+\\.\\d+(-.+)?$"
        let version_parts = ($core_version | split row ".")
        if (($version_parts | length) < 3) {
            $errors = ($errors | append {
                type: "invalid_version",
                severity: "error",
                field: "core.version",
                value: $core_version,
                message: $"core.version must follow semantic versioning format, got: ($core_version)"
            })
        }
    }

    # Validate debug.enabled is boolean
    let debug_enabled = ($config | get -o debug.enabled | default null)
    if ($debug_enabled | is-not-empty) {
        if (($debug_enabled | describe) != "bool") {
            $errors = ($errors | append {
                type: "invalid_type",
                severity: "error",
                field: "debug.enabled",
                value: $debug_enabled,
                expected: "bool",
                actual: ($debug_enabled | describe),
                message: $"debug.enabled must be boolean, got: ($debug_enabled | describe)"
            })
        }
    }

    # Validate debug.metadata is boolean
    let debug_metadata = ($config | get -o debug.metadata | default null)
    if ($debug_metadata | is-not-empty) {
        if (($debug_metadata | describe) != "bool") {
            $errors = ($errors | append {
                type: "invalid_type",
                severity: "error",
                field: "debug.metadata",
                value: $debug_metadata,
                expected: "bool",
                actual: ($debug_metadata | describe),
                message: $"debug.metadata must be boolean, got: ($debug_metadata | describe)"
            })
        }
    }

    # Validate sops.use_sops is boolean
    let sops_use = ($config | get -o sops.use_sops | default null)
    if ($sops_use | is-not-empty) {
        if (($sops_use | describe) != "bool") {
            $errors = ($errors | append {
                type: "invalid_type",
                severity: "error",
                field: "sops.use_sops",
                value: $sops_use,
                expected: "bool",
                actual: ($sops_use | describe),
                message: $"sops.use_sops must be boolean, got: ($sops_use | describe)"
            })
        }
    }

    {
        valid: (($errors | length) == 0),
        errors: $errors,
        warnings: $warnings
    }
}

# Validate semantic rules - business logic validation
export def validate-semantic-rules [
    config: record
] {
    mut errors = []
    mut warnings = []

    # Validate provider configuration
    let providers = ($config | get -o providers | default {})
    let default_provider = ($providers | get -o default | default null)

    if ($default_provider | is-not-empty) {
        let valid_providers = ["aws", "upcloud", "local"]
        if not ($default_provider in $valid_providers) {
            $errors = ($errors | append {
                type: "invalid_provider",
                severity: "error",
                field: "providers.default",
                value: $default_provider,
                valid_options: $valid_providers,
                message: $"Invalid default provider: ($default_provider). Valid options: ($valid_providers | str join ', ')"
            })
        }
    }

    # Validate log level
    let log_level = ($config | get -o debug.log_level | default null)
    if ($log_level | is-not-empty) {
        let valid_levels = ["trace", "debug", "info", "warn", "error"]
        if not ($log_level in $valid_levels) {
            $warnings = ($warnings | append {
                type: "invalid_log_level",
                severity: "warning",
                field: "debug.log_level",
                value: $log_level,
                valid_options: $valid_levels,
                message: $"Invalid log level: ($log_level). Valid options: ($valid_levels | str join ', ')"
            })
        }
    }

    # Validate output format
    let output_format = ($config | get -o output.format | default null)
    if ($output_format | is-not-empty) {
        let valid_formats = ["json", "yaml", "toml", "text"]
        if not ($output_format in $valid_formats) {
            $warnings = ($warnings | append {
                type: "invalid_output_format",
                severity: "warning",
                field: "output.format",
                value: $output_format,
                valid_options: $valid_formats,
                message: $"Invalid output format: ($output_format). Valid options: ($valid_formats | str join ', ')"
            })
        }
    }

    {
        valid: (($errors | length) == 0),
        errors: $errors,
        warnings: $warnings
    }
}

# Validate file existence - checks referenced files exist
export def validate-file-existence [
    config: record
] {
    mut errors = []
    mut warnings = []

    # Check SOPS configuration file
    let sops_config = ($config | get -o sops.config_path | default null)
    if ($sops_config | is-not-empty) {
        if not ($sops_config | path exists) {
            $warnings = ($warnings | append {
                type: "missing_sops_config",
                severity: "warning",
                field: "sops.config_path",
                value: $sops_config,
                message: $"SOPS config file not found: ($sops_config)"
            })
        }
    }

    # Check SOPS key files
    let key_paths = ($config | get -o sops.key_search_paths | default [])
    mut found_key = false

    for key_path in $key_paths {
        let expanded_path = ($key_path | str replace "~" $env.HOME)
        if ($expanded_path | path exists) {
            $found_key = true
            break
        }
    }

    if not $found_key and ($key_paths | length) > 0 {
        $warnings = ($warnings | append {
            type: "missing_sops_keys",
            severity: "warning",
            field: "sops.key_search_paths",
            value: $key_paths,
            message: $"No SOPS key files found in search paths: ($key_paths | str join ', ')"
        })
    }

    # Check critical configuration files
    let settings_file = ($config | get -o paths.files.settings | default null)
    if ($settings_file | is-not-empty) {
        if not ($settings_file | path exists) {
            $errors = ($errors | append {
                type: "missing_settings_file",
                severity: "error",
                field: "paths.files.settings",
                value: $settings_file,
                message: $"Settings file not found: ($settings_file)"
            })
        }
    }

    {
        valid: (($errors | length) == 0),
        errors: $errors,
        warnings: $warnings
    }
}

# Enhanced main validation function
export def validate-config [
    config: record
    --detailed = false              # Show detailed validation results
    --strict = false                # Treat warnings as errors
] {
    # Run all validation checks
    let structure_result = (validate-config-structure $config)
    let paths_result = (validate-path-values $config)
    let types_result = (validate-data-types $config)
    let semantic_result = (validate-semantic-rules $config)
    let files_result = (validate-file-existence $config)

    # Combine all results
    let all_errors = (
        $structure_result.errors | append $paths_result.errors | append $types_result.errors |
        append $semantic_result.errors | append $files_result.errors
    )

    let all_warnings = (
        $structure_result.warnings | append $paths_result.warnings | append $types_result.warnings |
        append $semantic_result.warnings | append $files_result.warnings
    )

    let has_errors = ($all_errors | length) > 0
    let has_warnings = ($all_warnings | length) > 0

    # In strict mode, treat warnings as errors
    let final_valid = if $strict {
        not $has_errors and not $has_warnings
    } else {
        not $has_errors
    }

    # Throw error if validation fails and not in detailed mode
    if not $detailed and not $final_valid {
        let error_messages = ($all_errors | each { |err| $err.message })
        let warning_messages = if $strict { ($all_warnings | each { |warn| $warn.message }) } else { [] }
        let combined_messages = ($error_messages | append $warning_messages)

        error make {
            msg: ($combined_messages | str join "; ")
        }
    }

    # Return detailed results
    {
        valid: $final_valid,
        errors: $all_errors,
        warnings: $all_warnings,
        summary: {
            total_errors: ($all_errors | length),
            total_warnings: ($all_warnings | length),
            checks_run: 5,
            structure_valid: $structure_result.valid,
            paths_valid: $paths_result.valid,
            types_valid: $types_result.valid,
            semantic_valid: $semantic_result.valid,
            files_valid: $files_result.valid
        }
    }
}
