"""Flow validation module.

Provides standalone flow validation that can be used independently
of FlowExecutor for lightweight CLI usage.
"""

from typing import Any

from pydantic import ValidationError

from agent_flows.core.flow_management import FlowLoader
from agent_flows.executors.registry import ExecutorRegistry
from agent_flows.models.flow import FlowConfig
from agent_flows.utils.validation import StepValidationResult, format_validation_errors


class FlowValidator:
    """Validates flow configurations.

    This class can be used standalone (for lightweight CLI usage)
    or as a delegate within FlowExecutor.

    Example standalone usage:
        validator = FlowValidator(flow_loader, executor_registry)
        result = await validator.validate(flow_config)
    """

    def __init__(
        self,
        flow_loader: FlowLoader,
        executor_registry: ExecutorRegistry,
    ):
        """Initialize the flow validator.

        Args:
            flow_loader: Loader for resolving flow sources to FlowConfig.
            executor_registry: Registry for validating step configurations.
        """
        self._flow_loader = flow_loader
        self._executor_registry = executor_registry

    async def validate(self, flow_source: FlowConfig | str) -> dict[str, Any]:
        """Validate a flow configuration.

        Args:
            flow_source: FlowConfig object, UUID string, or file path.

        Returns:
            Dictionary with validation results:
            {
                "valid": bool,
                "step_validation_summary": [
                    {
                        "step_id": str,
                        "step_type": str,
                        "valid": bool,
                        "messages": [str, ...]
                    },
                    ...
                ]
            }
        """
        try:
            flow_config = await self._flow_loader.load(flow_source)
            return self._validate_flow_config(flow_config)
        except Exception as e:
            return {
                "valid": False,
                "step_validation_summary": [
                    {
                        "step_id": "unknown",
                        "step_type": "unknown",
                        "valid": False,
                        "messages": [f"An unexpected error occurred during validation: {str(e)}"],
                    }
                ],
            }

    def _validate_flow_config(self, flow_config: FlowConfig) -> dict[str, Any]:
        """Validate a FlowConfig object."""
        step_results: list[dict[str, Any]] = []
        overall_valid = True

        # Track structural constraints
        seen_flow_variables = False
        seen_finish = False

        for step in flow_config.steps:
            step_result = StepValidationResult(step.id, step.type)

            try:
                # Legacy START step: allow passthrough without validation
                if step.type.lower() == "start":
                    step_results.append(step_result.to_dict())
                    continue

                # Structural validation: duplicate checks
                structural_issues = self._check_structural_rules(
                    step.type, seen_flow_variables, seen_finish
                )
                if "flow_variables" in structural_issues:
                    step_result.add_error(structural_issues["flow_variables"])
                else:
                    seen_flow_variables = seen_flow_variables or step.type == "flow_variables"

                if "finish" in structural_issues:
                    step_result.add_error(structural_issues["finish"])
                else:
                    seen_finish = seen_finish or step.type == "finish"

                # Step configuration validation
                self._validate_step(step, step_result)

            except Exception as e:
                step_result.add_error(f"Unexpected validation error: {str(e)}")

            if not step_result.valid:
                overall_valid = False

            step_results.append(step_result.to_dict())

        return {"valid": overall_valid, "step_validation_summary": step_results}

    def _check_structural_rules(
        self,
        step_type: str,
        seen_flow_variables: bool,
        seen_finish: bool,
    ) -> dict[str, str]:
        """Check flow-level structural rules.

        Returns dict of issues keyed by type.
        """
        issues: dict[str, str] = {}

        if step_type == "flow_variables" and seen_flow_variables:
            issues["flow_variables"] = "Only one flow_variables step is allowed"

        if step_type == "finish" and seen_finish:
            issues["finish"] = "Only one finish step is allowed"

        return issues

    def _validate_step(self, step: Any, step_result: StepValidationResult) -> None:
        """Validate individual step configuration."""
        # Check if executor is registered
        if not self._executor_registry.is_registered(step.type):
            step_result.add_error(f"Unknown step type '{step.type}'")
            return

        # Validate step config via executor
        try:
            self._executor_registry.validate_step_config(step.type, step.config)
        except ValidationError as e:
            error_messages = format_validation_errors(e, step.type)
            step_result.add_errors(error_messages)
        except Exception as e:
            step_result.add_error(str(e))
