"""Test helper for discovering available MCP models.

This module provides utilities for making tests model-agnostic
by discovering and using whatever models are available.
"""

import logging
from dataclasses import dataclass
from typing import Dict, List, Optional

from mcp_server_odoo.access_control import AccessController
from mcp_server_odoo.config import OdooConfig

logger = logging.getLogger(__name__)


@dataclass
class TestModelInfo:
    """Information about a model available for testing."""

    model: str
    can_read: bool
    can_write: bool
    can_create: bool
    can_unlink: bool

    @property
    def readable(self) -> bool:
        """Check if model is readable."""
        return self.can_read

    @property
    def writable(self) -> bool:
        """Check if model is writable."""
        return self.can_write

    @property
    def fully_accessible(self) -> bool:
        """Check if model has all permissions."""
        return all([self.can_read, self.can_write, self.can_create, self.can_unlink])


class ModelDiscovery:
    """Discovers available models for testing.

    This class helps tests adapt to whatever models are
    currently enabled in the MCP configuration.
    """

    def __init__(self, config: OdooConfig):
        """Initialize model discovery.

        Args:
            config: Odoo configuration
        """
        self.config = config
        self.controller = AccessController(config)
        self._cache: Optional[Dict[str, TestModelInfo]] = None

    def discover_models(self) -> Dict[str, TestModelInfo]:
        """Discover all available models and their permissions.

        Returns:
            Dictionary mapping model names to their test info
        """
        if self._cache is not None:
            return self._cache

        models = {}
        try:
            # Get all enabled models
            enabled = self.controller.get_enabled_models()

            for model_info in enabled:
                model_name = model_info.get("model")
                if not model_name:
                    continue

                # Get permissions for this model
                perms = self.controller.get_model_permissions(model_name)

                models[model_name] = TestModelInfo(
                    model=model_name,
                    can_read=perms.can_read,
                    can_write=perms.can_write,
                    can_create=perms.can_create,
                    can_unlink=perms.can_unlink,
                )

        except Exception as e:
            logger.warning(f"Failed to discover models: {e}")

        self._cache = models
        return models

    def get_readable_model(self) -> Optional[TestModelInfo]:
        """Get any model with read permission.

        Returns:
            TestModelInfo or None if no readable models
        """
        models = self.discover_models()

        for model in models.values():
            if model.readable:
                return model

        return None

    def get_writable_model(self) -> Optional[TestModelInfo]:
        """Get any model with write permission.

        Returns:
            TestModelInfo or None if no writable models
        """
        models = self.discover_models()

        for model in models.values():
            if model.writable:
                return model

        return None

    def get_fully_accessible_model(self) -> Optional[TestModelInfo]:
        """Get any model with all permissions.

        Returns:
            TestModelInfo or None if no fully accessible models
        """
        models = self.discover_models()

        for model in models.values():
            if model.fully_accessible:
                return model

        return None

    def get_common_models(self) -> List[TestModelInfo]:
        """Get commonly available models for testing.

        Prioritizes models like res.partner, res.users, etc.

        Returns:
            List of available common models
        """
        models = self.discover_models()
        common_model_names = [
            "res.partner",
            "res.users",
            "res.company",
            "product.product",
            "sale.order",
            "purchase.order",
        ]

        available = []
        for name in common_model_names:
            if name in models:
                available.append(models[name])

        return available

    def get_disabled_model(self) -> str:
        """Get a model name that is NOT enabled.

        Returns:
            Name of a model that should not be accessible
        """
        models = self.discover_models()

        # These system models are rarely enabled in MCP
        system_models = [
            "ir.model",
            "ir.model.fields",
            "ir.ui.view",
            "ir.rule",
            "base.automation",
            "ir.config_parameter",
            "ir.cron",
            "ir.module.module",
        ]

        for model in system_models:
            if model not in models:
                return model

        # If all system models are somehow enabled,
        # return a non-existent model
        return "non.existent.model"

    def require_readable_model(self) -> TestModelInfo:
        """Get a readable model or skip test.

        Returns:
            TestModelInfo for a readable model

        Raises:
            pytest.skip if no readable models available
        """
        import pytest

        model = self.get_readable_model()
        if not model:
            pytest.skip("No readable models available for testing")

        return model

    def require_writable_model(self) -> TestModelInfo:
        """Get a writable model or skip test.

        Returns:
            TestModelInfo for a writable model

        Raises:
            pytest.skip if no writable models available
        """
        import pytest

        model = self.get_writable_model()
        if not model:
            pytest.skip("No writable models available for testing")

        return model
