"""Microsoft Teams Bot service for approval notifications via Adaptive Cards."""
import time
from typing import Optional, TYPE_CHECKING

import httpx
from loguru import logger

from src.config import settings

if TYPE_CHECKING:
    from src.database.models import TeamsAccount

# Bot auth token cache: (token_string, expiry_timestamp)
_bot_token_cache: Optional[tuple[str, float]] = None

# JWKS cache: (keys_list, expiry_timestamp)
_jwks_cache: Optional[tuple[list, float]] = None
_JWKS_TTL = 3600  # 1 hour


class TeamsService:
    """Handles Microsoft Teams bot interactions for post approval notifications."""

    def __init__(self, app_id: str, app_secret: str, tenant_id: str = "botframework.com"):
        self._app_id = app_id
        self._app_secret = app_secret
        self._tenant_id = tenant_id

    # ==================== BOT AUTH TOKEN ====================

    async def get_bot_token(self) -> str:
        """Get a valid bot framework OAuth token, using module-level cache (~50 min TTL)."""
        global _bot_token_cache

        now = time.monotonic()
        if _bot_token_cache and _bot_token_cache[1] > now + 60:
            return _bot_token_cache[0]

        async with httpx.AsyncClient(timeout=15.0) as client:
            resp = await client.post(
                f"https://login.microsoftonline.com/{self._tenant_id}/oauth2/v2.0/token",
                data={
                    "grant_type": "client_credentials",
                    "client_id": self._app_id,
                    "client_secret": self._app_secret,
                    "scope": "https://api.botframework.com/.default",
                },
            )
            resp.raise_for_status()
            data = resp.json()

        token = data["access_token"]
        expires_in = int(data.get("expires_in", 3600))
        # Cache for expires_in minus 60 seconds safety margin
        _bot_token_cache = (token, now + expires_in - 60)
        logger.debug("Fetched new Teams bot token")
        return token

    # ==================== JWT VALIDATION ====================

    async def _get_jwks(self) -> list:
        """Fetch and cache JWKS from Bot Framework OpenID configuration."""
        global _jwks_cache

        now = time.monotonic()
        if _jwks_cache and _jwks_cache[1] > now:
            return _jwks_cache[0]

        async with httpx.AsyncClient(timeout=15.0) as client:
            oid_resp = await client.get(
                "https://login.botframework.com/v1/.well-known/openidconfiguration"
            )
            oid_resp.raise_for_status()
            jwks_uri = oid_resp.json()["jwks_uri"]

            jwks_resp = await client.get(jwks_uri)
            jwks_resp.raise_for_status()
            keys = jwks_resp.json()["keys"]

        _jwks_cache = (keys, now + _JWKS_TTL)
        return keys

    async def validate_incoming_token(self, auth_header: str) -> bool:
        """Validate the JWT Bearer token from an incoming Teams webhook request."""
        try:
            import jwt
            from jwt.algorithms import RSAAlgorithm

            if not auth_header.startswith("Bearer "):
                return False
            token = auth_header[7:]

            keys = await self._get_jwks()

            # Try each key until one validates
            for key_data in keys:
                try:
                    public_key = RSAAlgorithm.from_jwk(key_data)
                    jwt.decode(
                        token,
                        public_key,
                        algorithms=["RS256"],
                        audience=self._app_id,
                    )
                    return True
                except jwt.PyJWTError:
                    continue

            return False
        except Exception as e:
            logger.warning(f"Teams JWT validation error: {e}")
            return False

    # ==================== SEND PROACTIVE MESSAGE ====================

    async def _send_activity(
        self, teams_account: "TeamsAccount", activity: dict
    ) -> None:
        """Post an activity to a Teams conversation."""
        token = await self.get_bot_token()
        service_url = teams_account.teams_service_url.rstrip("/")
        conversation_id = teams_account.teams_conversation_id

        url = f"{service_url}/v3/conversations/{conversation_id}/activities"
        async with httpx.AsyncClient(timeout=15.0) as client:
            resp = await client.post(
                url,
                json=activity,
                headers={"Authorization": f"Bearer {token}"},
            )
            resp.raise_for_status()

    async def send_text_message(self, teams_account: "TeamsAccount", text: str) -> None:
        """Send a plain text message to a Teams conversation."""
        await self._send_activity(
            teams_account,
            {
                "type": "message",
                "text": text,
            },
        )

    async def send_approval_card(
        self,
        teams_account: "TeamsAccount",
        post_title: str,
        post_content: str,
        approve_token: str,
        reject_token: str,
        company_name: str,
    ) -> None:
        """Send an Adaptive Card with approve/reject buttons to a Teams conversation."""
        preview = (post_content[:300] + "…") if len(post_content) > 300 else post_content

        card = {
            "type": "AdaptiveCard",
            "version": "1.4",
            "body": [
                {
                    "type": "TextBlock",
                    "text": "Post zur Freigabe",
                    "weight": "Bolder",
                    "size": "Medium",
                },
                {
                    "type": "TextBlock",
                    "text": f"{company_name} hat deinen Post bearbeitet:",
                    "wrap": True,
                    "color": "Accent",
                },
                {
                    "type": "TextBlock",
                    "text": post_title,
                    "wrap": True,
                    "weight": "Bolder",
                },
                {
                    "type": "TextBlock",
                    "text": preview,
                    "wrap": True,
                    "maxLines": 6,
                    "color": "Default",
                },
            ],
            "actions": [
                {
                    "type": "Action.Execute",
                    "title": "✅ Freigeben",
                    "style": "positive",
                    "data": {"action": "approve", "token": approve_token},
                },
                {
                    "type": "Action.Execute",
                    "title": "❌ Ablehnen",
                    "style": "destructive",
                    "data": {"action": "reject", "token": reject_token},
                },
            ],
        }

        await self._send_activity(
            teams_account,
            {
                "type": "message",
                "attachments": [
                    {
                        "contentType": "application/vnd.microsoft.card.adaptive",
                        "content": card,
                    }
                ],
            },
        )


# Module-level singleton — only created when Teams is enabled
teams_service: Optional[TeamsService] = None
if settings.teams_enabled:
    teams_service = TeamsService(
        settings.microsoft_app_id,
        settings.microsoft_app_secret,
        settings.microsoft_app_tenant_id,
    )
