import inspect
from typing import List, Optional

from sqlalchemy import select

from acex.models import LogicalNode, LogicalNodeResponse, PaginatedResponse
from acex.models.node import Node


class LogicalNodeService:
    """Service layer för LogicalNode business logic inklusive kompilering."""
    
    def __init__(self, adapter, config_compiler, integrations):
        self.adapter = adapter
        self.config_compiler = config_compiler
        self.integrations = integrations
    
    async def _call_method(self, method, *args, **kwargs):
        """Helper för att hantera både sync och async metoder."""
        if inspect.iscoroutinefunction(method):
            return await method(*args, **kwargs)
        else:
            return method(*args, **kwargs)
    
    async def _apply_compilation(self, logical_node, resolve:bool = False):
        """Helper för att applicera kompilering sync eller async."""
        if self.config_compiler and logical_node:
            if inspect.iscoroutinefunction(self.config_compiler.compile):
                return await self.config_compiler.compile(logical_node, self.integrations, resolve)
            else:
                return self.config_compiler.compile(logical_node, self.integrations, resolve)
        return logical_node
    
    async def create(self, logical_node: LogicalNode):
        result = await self._call_method(self.adapter.create, logical_node)
        return result
    
    async def get(self, id: str, resolve: bool = False) -> LogicalNodeResponse:

        # Fetch LN from plugin:
        ln = await self._call_method(self.adapter.get, id)

        # Compile
        ln = await self._apply_compilation(ln, resolve=resolve)
        return ln
    
    async def query(
        self,
        role: str = None,
        site: str = None,
        sequence: int = None,
        hostname: str = None,
        assigned: Optional[bool] = None,
        limit: int = 100,
        offset: int = 0,
    )-> PaginatedResponse[LogicalNode]:

        query_filters = {
            k: v for k, v in {
                "role": role,
                "site": site,
                "sequence": sequence,
                "hostname": hostname,
            }.items() if v is not None
        }

        extra_filters = []
        if assigned is not None:
            assigned_ids = select(Node.logical_node_id)
            if assigned:
                extra_filters.append(LogicalNode.id.in_(assigned_ids))
            else:
                extra_filters.append(~LogicalNode.id.in_(assigned_ids))

        result = await self._call_method(self.adapter.query, filters=query_filters, extra_filters=extra_filters or None, limit=limit, offset=offset)
        return PaginatedResponse(items=result["items"], total=result["total"], limit=limit, offset=offset)
    
    async def update(self, id: str, logical_node: LogicalNode):
        result = await self._call_method(self.adapter.update, id, logical_node)
        return result
    
    async def delete(self, id: str):
        result = await self._call_method(self.adapter.delete, id)
        return result
    
    @property
    def capabilities(self):
        return self.adapter.capabilities
    
    def path(self, capability):
        return self.adapter.path(capability)
    
    def http_verb(self, capability):
        return self.adapter.http_verb(capability)
