"""Project validator for Hephaestus."""

from __future__ import annotations

from pathlib import Path
from typing import List

from ..dependencies.container import FileSystem, ProjectManager


class ProjectValidator:
    """Validate Anvil project structure and requirements."""

    def __init__(self, file_system: FileSystem, project_manager: ProjectManager):
        self.file_system = file_system
        self.project_manager = project_manager

    def validate_project_structure(self, project_path: Path) -> tuple[bool, List[str]]:
        """Validate basic Anvil project structure."""
        errors = []

        if not project_path.exists():
            errors.append(f"Project path does not exist: {project_path}")
            return False, errors

        if not self.project_manager.is_anvil_project(project_path):
            errors.append("Not a valid Anvil project - missing required files")
            return False, errors

        # Check required directories
        required_dirs = ["client_code", "server_code"]
        for dir_name in required_dirs:
            dir_path = project_path / dir_name
            if not dir_path.exists():
                errors.append(f"Missing required directory: {dir_name}")

        # Check optional but recommended directories
        recommended_dirs = ["theme", "assets", "modules"]
        for dir_name in recommended_dirs:
            dir_path = project_path / dir_name
            if not dir_path.exists():
                errors.append(f"Missing recommended directory: {dir_name}")

        return len(errors) == 0, errors

    def validate_dependencies(self, project_path: Path) -> tuple[bool, List[str]]:
        """Validate project dependencies and versions."""
        errors = []

        # Check for app.json
        app_json_path = project_path / "app.json"
        if not app_json_path.exists():
            errors.append("Missing app.json file")
            return False, errors

        try:
            content = self.file_system.read_text(app_json_path)
            import json

            app_data = json.loads(content)

            # Validate required fields
            required_fields = ["title", "runtime_version"]
            for field in required_fields:
                if field not in app_data:
                    errors.append(f"Missing required field in app.json: {field}")

            # Validate runtime version
            runtime_version = app_data.get("runtime_version", "")
            if not self._is_valid_anvil_version(runtime_version):
                errors.append(f"Invalid Anvil runtime version: {runtime_version}")

        except json.JSONDecodeError:
            errors.append("Invalid JSON in app.json file")
        except Exception:
            errors.append("Error reading app.json file")

        return len(errors) == 0, errors

    def validate_client_code(self, project_path: Path) -> tuple[bool, List[str]]:
        """Validate client code structure and quality."""
        errors = []

        client_dir = project_path / "client_code"
        if not client_dir.exists():
            errors.append("Client code directory missing")
            return False, errors

        # Check for at least one form
        client_files = self.project_manager.get_project_files(
            project_path, "client_code/**/*.py"
        )
        if not client_files:
            errors.append("No client code files found")
            return False, errors

        form_count = 0
        for file_path in client_files:
            content = self.file_system.read_text(file_path)
            if self._contains_form_class(content):
                form_count += 1

        if form_count == 0:
            errors.append("No form classes found in client code")

        return len(errors) == 0, errors

    def validate_server_code(self, project_path: Path) -> tuple[bool, List[str]]:
        """Validate server code structure and quality."""
        errors = []

        server_dir = project_path / "server_code"
        if not server_dir.exists():
            errors.append("Server code directory missing")
            return False, errors

        server_files = self.project_manager.get_project_files(
            project_path, "server_code/**/*.py"
        )
        if not server_files:
            errors.append("No server code files found")
            return False, errors

        # Check for server functions
        has_callable = False
        for file_path in server_files:
            content = self.file_system.read_text(file_path)
            if "@anvil.server.callable" in content:
                has_callable = True
                break

        if not has_callable:
            errors.append("No server callable functions found")

        return len(errors) == 0, errors

    def validate_theme_structure(self, project_path: Path) -> tuple[bool, List[str]]:
        """Validate theme structure and files."""
        errors = []

        theme_dir = project_path / "theme"
        if not theme_dir.exists():
            return True, errors  # Theme is optional

        # Check theme files
        theme_files = self.project_manager.get_project_files(project_path, "theme/**/*")
        if not theme_files:
            errors.append("Theme directory exists but contains no files")

        # Check for theme.yaml
        theme_yaml = theme_dir / "theme.yaml"
        if theme_yaml.exists():
            try:
                content = self.file_system.read_text(theme_yaml)
                import yaml

                yaml.safe_load(content)
            except yaml.YAMLError:
                errors.append("Invalid YAML in theme.yaml")

        return len(errors) == 0, errors

    def validate_asset_structure(self, project_path: Path) -> tuple[bool, List[str]]:
        """Validate asset structure and files."""
        errors = []

        assets_dir = project_path / "assets"
        if not assets_dir.exists():
            return True, errors  # Assets are optional

        # Check for common asset types
        asset_types = ["images", "fonts", "css", "js"]
        found_assets = set()

        for asset_type in asset_types:
            asset_path = assets_dir / asset_type
            if asset_path.exists():
                found_assets.add(asset_type)

        if not found_assets:
            errors.append(
                "Assets directory exists but contains no asset subdirectories"
            )

        return len(errors) == 0, errors

    def validate_module_structure(self, project_path: Path) -> tuple[bool, List[str]]:
        """Validate module structure and dependencies."""
        errors = []

        modules_dir = project_path / "modules"
        if not modules_dir.exists():
            return True, errors  # Modules are optional

        # Check module files
        module_files = self.project_manager.get_project_files(
            project_path, "modules/**/*.py"
        )
        if not module_files:
            errors.append("Modules directory exists but contains no Python files")

        return len(errors) == 0, errors

    def validate_configuration(self, project_path: Path) -> tuple[bool, List[str]]:
        """Validate project configuration files."""
        errors = []

        # Check for configuration files
        config_files = ["app.json", "package.json", "requirements.txt", "anvil.yaml"]

        for config_file in config_files:
            file_path = project_path / config_file
            if file_path.exists():
                if config_file.endswith(".json"):
                    if not self._validate_json_file(file_path):
                        errors.append(f"Invalid JSON in {config_file}")
                elif config_file.endswith(".yaml"):
                    if not self._validate_yaml_file(file_path):
                        errors.append(f"Invalid YAML in {config_file}")

        return len(errors) == 0, errors

    def _is_valid_anvil_version(self, version: str) -> bool:
        """Check if Anvil version is valid."""
        if not version:
            return False

        # Simple version validation - could be enhanced with actual version list
        version_parts = version.split(".")
        if len(version_parts) < 2:
            return False

        try:
            major = int(version_parts[0])
            minor = int(version_parts[1])
            return major >= 1 and minor >= 0
        except ValueError:
            return False

    def _contains_form_class(self, content: str) -> bool:
        """Check if Python file contains a form class."""
        import re

        return bool(re.search(r"class\s+\w+\([^)]*Form[^)]*\):", content))

    def _validate_json_file(self, file_path: Path) -> bool:
        """Validate JSON file syntax."""
        try:
            content = self.file_system.read_text(file_path)
            import json

            json.loads(content)
            return True
        except json.JSONDecodeError:
            return False

    def _validate_yaml_file(self, file_path: Path) -> bool:
        """Validate YAML file syntax."""
        try:
            content = self.file_system.read_text(file_path)
            import yaml

            yaml.safe_load(content)
            return True
        except yaml.YAMLError:
            return False
