"""Policy YAML schema validation."""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any

import jsonschema
import yaml

# JSON Schema for policy files
POLICY_SCHEMA: dict[str, Any] = {
    "$schema": "http://json-schema.org/draft-07/schema#",
    "type": "object",
    "required": ["version", "policies"],
    "properties": {
        "version": {
            "type": "string",
            "pattern": "^\\d+\\.\\d+$",
            "description": "Schema version (e.g., '1.0')",
        },
        "metadata": {
            "type": "object",
            "properties": {
                "name": {"type": "string"},
                "description": {"type": "string"},
                "author": {"type": "string"},
                "url": {"type": "string", "format": "uri"},
            },
        },
        "policies": {
            "type": "array",
            "minItems": 1,
            "items": {
                "type": "object",
                "required": ["id", "name", "rules"],
                "properties": {
                    "id": {
                        "type": "string",
                        "pattern": "^[a-z][a-z0-9-]*$",
                        "description": "Unique policy identifier",
                    },
                    "name": {
                        "type": "string",
                        "description": "Human-readable policy name",
                    },
                    "description": {
                        "type": "string",
                        "description": "Policy description",
                    },
                    "severity": {
                        "type": "string",
                        "enum": ["error", "warning", "info"],
                        "default": "warning",
                    },
                    "languages": {
                        "type": "array",
                        "items": {"type": "string"},
                        "default": ["*"],
                        "description": "Languages this policy applies to",
                    },
                    "enabled": {
                        "type": "boolean",
                        "default": True,
                    },
                    "rules": {
                        "type": "array",
                        "minItems": 1,
                        "items": {
                            "type": "object",
                            "required": ["pattern", "message"],
                            "properties": {
                                "pattern": {
                                    "type": "string",
                                    "description": "Regex pattern to match",
                                },
                                "flags": {
                                    "type": "string",
                                    "pattern": "^[imsx]*$",
                                    "default": "",
                                    "description": "Regex flags (i=case, m=multiline, s=dotall)",
                                },
                                "message": {
                                    "type": "string",
                                    "description": "Message to display on match",
                                },
                                "remediation": {
                                    "type": "string",
                                    "description": "How to fix this issue",
                                },
                            },
                        },
                    },
                },
            },
        },
    },
}


@dataclass
class PolicyRule:
    """A single rule within a policy."""

    pattern: str
    message: str
    flags: str = ""
    remediation: str = ""


@dataclass
class Policy:
    """A single policy definition."""

    id: str
    name: str
    rules: list[PolicyRule]
    description: str = ""
    severity: str = "warning"
    languages: list[str] = field(default_factory=lambda: ["*"])
    enabled: bool = True


@dataclass
class PolicyMetadata:
    """Metadata for a policy file."""

    name: str = ""
    description: str = ""
    author: str = ""
    url: str = ""


@dataclass
class PolicyFile:
    """A complete policy file."""

    version: str
    policies: list[Policy]
    metadata: PolicyMetadata = field(default_factory=PolicyMetadata)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> PolicyFile:
        """Create a PolicyFile from a dictionary."""
        metadata_data = data.get("metadata", {})
        metadata = PolicyMetadata(
            name=metadata_data.get("name", ""),
            description=metadata_data.get("description", ""),
            author=metadata_data.get("author", ""),
            url=metadata_data.get("url", ""),
        )

        policies = []
        for policy_data in data.get("policies", []):
            rules = [
                PolicyRule(
                    pattern=rule["pattern"],
                    message=rule["message"],
                    flags=rule.get("flags", ""),
                    remediation=rule.get("remediation", ""),
                )
                for rule in policy_data.get("rules", [])
            ]
            policies.append(
                Policy(
                    id=policy_data["id"],
                    name=policy_data["name"],
                    rules=rules,
                    description=policy_data.get("description", ""),
                    severity=policy_data.get("severity", "warning"),
                    languages=policy_data.get("languages", ["*"]),
                    enabled=policy_data.get("enabled", True),
                )
            )

        return cls(
            version=data["version"],
            policies=policies,
            metadata=metadata,
        )

    @classmethod
    def from_yaml(cls, yaml_content: str) -> PolicyFile:
        """Parse a policy file from YAML content."""
        data = yaml.safe_load(yaml_content)
        return cls.from_dict(data)


class PolicySchema:
    """Validator for policy files."""

    def __init__(self) -> None:
        self.validator = jsonschema.Draft7Validator(POLICY_SCHEMA)

    def validate(self, data: dict[str, Any]) -> list[str]:
        """Validate a policy dictionary.

        Args:
            data: Policy data to validate

        Returns:
            List of validation error messages (empty if valid)
        """
        errors = []
        for error in self.validator.iter_errors(data):
            path = ".".join(str(p) for p in error.absolute_path)
            if path:
                errors.append(f"{path}: {error.message}")
            else:
                errors.append(error.message)
        return errors

    def validate_yaml(self, yaml_content: str) -> list[str]:
        """Validate a YAML policy file.

        Args:
            yaml_content: YAML content to validate

        Returns:
            List of validation error messages (empty if valid)
        """
        try:
            data = yaml.safe_load(yaml_content)
        except yaml.YAMLError as e:
            return [f"YAML parsing error: {e}"]

        if not isinstance(data, dict):
            return ["Policy file must be a YAML object"]

        return self.validate(data)

    def is_valid(self, data: dict[str, Any]) -> bool:
        """Check if a policy dictionary is valid."""
        return len(self.validate(data)) == 0


def validate_policy_file(yaml_content: str) -> tuple[bool, list[str]]:
    """Validate a policy YAML file.

    Args:
        yaml_content: YAML content to validate

    Returns:
        Tuple of (is_valid, error_messages)
    """
    schema = PolicySchema()
    errors = schema.validate_yaml(yaml_content)
    return len(errors) == 0, errors
