from __future__ import annotations

import asyncio
import logging
import aiohttp

from langbot.pkg.utils import httpclient
import uuid
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from ..core import app

import langbot_plugin.api.entities.builtin.platform.events as platform_events


class WebhookPusher:
    """Push bot events to configured webhooks"""

    ap: app.Application
    logger: logging.Logger

    def __init__(self, ap: app.Application):
        self.ap = ap
        self.logger = self.ap.logger

    async def push_person_message(self, event: platform_events.FriendMessage, bot_uuid: str, adapter_name: str) -> bool:
        """Push person message event to webhooks

        Returns:
            bool: True if any webhook responded with skip_pipeline=true, False otherwise
        """
        try:
            webhooks = await self.ap.webhook_service.get_enabled_webhooks()
            if not webhooks:
                return False

            # Build payload
            payload = {
                'uuid': str(uuid.uuid4()),  # unique id for the event
                'event_type': 'bot.person_message',
                'data': {
                    'bot_uuid': bot_uuid,
                    'adapter_name': adapter_name,
                    'sender': {
                        'id': str(event.sender.id),
                        'name': getattr(event.sender, 'name', ''),
                    },
                    'message': event.message_chain.model_dump(),
                    'timestamp': event.time if hasattr(event, 'time') else None,
                },
            }

            # Push to all webhooks asynchronously
            tasks = [self._push_to_webhook(webhook['url'], payload) for webhook in webhooks]
            results = await asyncio.gather(*tasks, return_exceptions=True)

            # Check if any webhook responded with skip_pipeline=true
            for result in results:
                if isinstance(result, dict) and result.get('skip_pipeline') is True:
                    self.logger.info('Webhook responded with skip_pipeline=true, skipping pipeline for person message')
                    return True

            return False

        except Exception as e:
            self.logger.error(f'Failed to push person message to webhooks: {e}')
            return False

    async def push_group_message(self, event: platform_events.GroupMessage, bot_uuid: str, adapter_name: str) -> bool:
        """Push group message event to webhooks

        Returns:
            bool: True if any webhook responded with skip_pipeline=true, False otherwise
        """
        try:
            webhooks = await self.ap.webhook_service.get_enabled_webhooks()
            if not webhooks:
                return False

            # Build payload
            payload = {
                'uuid': str(uuid.uuid4()),  # unique id for the event
                'event_type': 'bot.group_message',
                'data': {
                    'bot_uuid': bot_uuid,
                    'adapter_name': adapter_name,
                    'group': {
                        'id': str(event.group.id),
                        'name': getattr(event.group, 'name', ''),
                    },
                    'sender': {
                        'id': str(event.sender.id),
                        'name': getattr(event.sender, 'name', ''),
                    },
                    'message': event.message_chain.model_dump(),
                    'timestamp': event.time if hasattr(event, 'time') else None,
                },
            }

            # Push to all webhooks asynchronously
            tasks = [self._push_to_webhook(webhook['url'], payload) for webhook in webhooks]
            results = await asyncio.gather(*tasks, return_exceptions=True)

            # Check if any webhook responded with skip_pipeline=true
            for result in results:
                if isinstance(result, dict) and result.get('skip_pipeline') is True:
                    self.logger.info('Webhook responded with skip_pipeline=true, skipping pipeline for group message')
                    return True

            return False

        except Exception as e:
            self.logger.error(f'Failed to push group message to webhooks: {e}')
            return False

    async def _push_to_webhook(self, url: str, payload: dict) -> dict | None:
        """Push payload to a single webhook URL

        Returns:
            dict | None: The response JSON if successful, None otherwise
        """
        try:
            session = httpclient.get_session()
            async with session.post(
                url,
                json=payload,
                headers={'Content-Type': 'application/json'},
                timeout=aiohttp.ClientTimeout(total=15),
            ) as response:
                if response.status >= 400:
                    self.logger.warning(f'Webhook {url} returned status {response.status}')
                    return None
                else:
                    self.logger.debug(f'Successfully pushed to webhook {url}')
                    try:
                        return await response.json()
                    except Exception as json_error:
                        self.logger.debug(f'Failed to parse JSON response from webhook {url}: {json_error}')
                        return None
        except asyncio.TimeoutError:
            self.logger.warning(f'Timeout pushing to webhook {url}')
            return None
        except Exception as e:
            self.logger.warning(f'Error pushing to webhook {url}: {e}')
            return None
