from dataclasses import dataclass
from typing import Dict, List, Any, Optional
from abc import ABC, abstractmethod
from enum import Enum


@dataclass
class Host:
    name: str
    default_url: str

    def get_env_var(self) -> str:
        return f"{self.name.upper()}_URL"


class OAuth2FlowType(Enum):
    AUTHORIZATION_CODE = "authorizationCode"
    IMPLICIT = "implicit"
    PASSWORD = "password"
    CLIENT_CREDENTIALS = "clientCredentials"


@dataclass
class OAuth2Flow:
    authorization_url: Optional[str] = None
    token_url: Optional[str] = None
    refresh_url: Optional[str] = None
    scopes: Optional[Dict[str, str]] = None


@dataclass
class SecurityScheme(ABC):
    id: str

    @classmethod
    @abstractmethod
    def from_dict(cls, json_data) -> "SecurityScheme":
        scheme_type = json_data.get("type")
        if scheme_type == "apiKey":
            return ApiKeySecurityScheme.from_dict(json_data)
        elif scheme_type == "oauth2":
            return OAuth2SecurityScheme.from_dict(json_data)
        elif scheme_type == "http":
            return HttpSecurityScheme.from_dict(json_data)
        raise ValueError(f"Unsupported security scheme type: {scheme_type}")

    @abstractmethod
    def to_dict(self) -> Dict[str, Any]:
        pass


@dataclass
class ApiKeySecurityScheme(SecurityScheme):
    type: str = "apiKey"
    name: str = ""
    in_field: str = ""

    @classmethod
    def from_dict(cls, json_data) -> "ApiKeySecurityScheme":
        return cls(id=json_data["id"], name=json_data["name"], in_field=json_data["in"])

    def to_dict(self) -> Dict[str, Any]:
        return {
            "id": self.id,
            "type": self.type,
            "name": self.name,
            "in": self.in_field,
        }


@dataclass
class OAuth2SecurityScheme(SecurityScheme):
    type: str = "oauth2"
    flows: Dict[OAuth2FlowType, OAuth2Flow] = None

    @classmethod
    def from_dict(cls, json_data) -> "OAuth2SecurityScheme":
        flows = {}
        for flow_type, flow_data in json_data.get("flows", {}).items():
            try:
                flow_type_enum = OAuth2FlowType(flow_type)
                flows[flow_type_enum] = OAuth2Flow(
                    authorization_url=flow_data.get("authorizationUrl"),
                    token_url=flow_data.get("tokenUrl"),
                    refresh_url=flow_data.get("refreshUrl"),
                    scopes=flow_data.get("scopes", {}),
                )
            except ValueError:
                continue

        return cls(id=json_data["id"], flows=flows)

    def to_dict(self) -> Dict[str, Any]:
        return {
            "id": self.id,
            "type": self.type,
            "flows": {
                flow_type.value: {
                    "authorizationUrl": flow.authorization_url,
                    "tokenUrl": flow.token_url,
                    "refreshUrl": flow.refresh_url,
                    "scopes": flow.scopes,
                }
                for flow_type, flow in self.flows.items()
            },
        }


@dataclass
class HttpSecurityScheme(SecurityScheme):
    type: str = "http"
    scheme: str = "bearer"
    bearer_format: Optional[str] = None
    description: Optional[str] = None

    @classmethod
    def from_dict(cls, json_data) -> "HttpSecurityScheme":
        return cls(
            id=json_data["id"],
            scheme=json_data["scheme"],
            bearer_format=json_data.get("bearerFormat"),
            description=json_data.get("description"),
        )

    def to_dict(self) -> Dict[str, Any]:
        result = {
            "id": self.id,
            "type": self.type,
            "scheme": self.scheme,
        }
        if self.bearer_format:
            result["bearerFormat"] = self.bearer_format
        if self.description:
            result["description"] = self.description
        return result


@dataclass
class Tool:
    name: str
    description: str
    input_schema: dict
    hive: str
    security_schemes: List[SecurityScheme]
    host: Host

    def get_required_env_vars(self) -> Dict[str, str]:
        """Get all required environment variables for this tool.

        Returns:
            Dict mapping environment variable names to their descriptions
        """
        env_vars = {}
        env_vars[self.host.get_env_var()] = f"Server URL for {self.host.name}"
        return env_vars

    def to_llm_tool(self):
        return {
            "name": self.name,
            "description": self.description,
            "input_schema": self.input_schema,
        }


class AuthStatus(Enum):
    NO_AUTHENTICATION_REQUIRED = "NO_AUTHENTICATION_REQUIRED"
    UNAUTHENTICATED = "UNAUTHENTICATED"
    PARTIALLY_AUTHENTICATED = "PARTIALLY_AUTHENTICATED"
    AUTHENTICATED = "AUTHENTICATED"
