from __future__ import annotations

import sqlalchemy

from ....core import app
from ....entity.persistence import webhook
from .secrets import SECRET_MASK, mask_secret_value, restore_secret_placeholders
from .tenant import TenantContext, require_workspace_uuid, scope_statement


_DEFAULT_MAX_WEBHOOKS_PER_WORKSPACE = 16
_HARD_MAX_WEBHOOKS_PER_WORKSPACE = 64


class WebhookService:
    ap: app.Application

    def __init__(self, ap: app.Application) -> None:
        self.ap = ap

    def max_per_workspace(self) -> int:
        """Return the configured webhook cap within the process hard limit."""

        config = getattr(getattr(self.ap, 'instance_config', None), 'data', {})
        try:
            value = int(
                config.get('webhooks', {}).get(
                    'max_per_workspace',
                    _DEFAULT_MAX_WEBHOOKS_PER_WORKSPACE,
                )
            )
        except (AttributeError, TypeError, ValueError):
            value = _DEFAULT_MAX_WEBHOOKS_PER_WORKSPACE
        return min(max(value, 1), _HARD_MAX_WEBHOOKS_PER_WORKSPACE)

    def _serialize_webhook(self, entity, *, include_secret: bool) -> dict:
        serialized = self.ap.persistence_mgr.serialize_model(webhook.Webhook, entity)
        if not include_secret:
            serialized = serialized.copy()
            serialized['url'] = mask_secret_value(serialized.get('url'))
        return serialized

    async def get_webhooks(self, context: TenantContext, *, include_secret: bool = False) -> list[dict]:
        """Get all webhooks"""
        result = await self.ap.persistence_mgr.execute_async(
            scope_statement(
                sqlalchemy.select(webhook.Webhook).order_by(webhook.Webhook.id).limit(_HARD_MAX_WEBHOOKS_PER_WORKSPACE),
                webhook.Webhook,
                context,
            )
        )

        webhooks = result.all()
        return [self._serialize_webhook(wh, include_secret=include_secret) for wh in webhooks]

    async def create_webhook(
        self,
        context: TenantContext,
        name: str,
        url: str,
        description: str = '',
        enabled: bool = True,
    ) -> dict:
        """Create a new webhook"""
        workspace_uuid = require_workspace_uuid(context)
        max_webhooks = self.max_per_workspace()
        count_result = await self.ap.persistence_mgr.execute_async(
            sqlalchemy.select(sqlalchemy.func.count())
            .select_from(webhook.Webhook)
            .where(webhook.Webhook.workspace_uuid == workspace_uuid)
        )
        if (count_result.scalar() or 0) >= max_webhooks:
            raise ValueError(f'Maximum number of webhooks ({max_webhooks}) reached')

        url = restore_secret_placeholders(url, sensitive=True)
        webhook_data = {
            'workspace_uuid': workspace_uuid,
            'name': name,
            'url': url,
            'description': description,
            'enabled': enabled,
        }

        insert_result = await self.ap.persistence_mgr.execute_async(
            sqlalchemy.insert(webhook.Webhook).values(**webhook_data)
        )

        # Retrieve the created webhook
        result = await self.ap.persistence_mgr.execute_async(
            scope_statement(
                sqlalchemy.select(webhook.Webhook).where(webhook.Webhook.id == insert_result.inserted_primary_key[0]),
                webhook.Webhook,
                workspace_uuid,
            )
        )
        created_webhook = result.first()

        return self.ap.persistence_mgr.serialize_model(webhook.Webhook, created_webhook)

    async def get_webhook(
        self,
        context: TenantContext,
        webhook_id: int,
        *,
        include_secret: bool = False,
    ) -> dict | None:
        """Get a specific webhook by ID"""
        result = await self.ap.persistence_mgr.execute_async(
            scope_statement(
                sqlalchemy.select(webhook.Webhook).where(webhook.Webhook.id == webhook_id),
                webhook.Webhook,
                context,
            )
        )

        wh = result.first()

        if wh is None:
            return None

        return self._serialize_webhook(wh, include_secret=include_secret)

    async def update_webhook(
        self,
        context: TenantContext,
        webhook_id: int,
        name: str | None = None,
        url: str | None = None,
        description: str | None = None,
        enabled: bool | None = None,
    ) -> bool:
        """Update a webhook's metadata"""
        update_data = {}
        if name is not None:
            update_data['name'] = name
        if url is not None:
            if url == SECRET_MASK:
                current = await self.get_webhook(context, webhook_id, include_secret=True)
                if current is None:
                    return False
                url = restore_secret_placeholders(url, current.get('url'), sensitive=True)
            update_data['url'] = url
        if description is not None:
            update_data['description'] = description
        if enabled is not None:
            update_data['enabled'] = enabled

        if update_data:
            result = await self.ap.persistence_mgr.execute_async(
                scope_statement(
                    sqlalchemy.update(webhook.Webhook).where(webhook.Webhook.id == webhook_id).values(**update_data),
                    webhook.Webhook,
                    context,
                )
            )
            return (result.rowcount or 0) > 0
        return await self.get_webhook(context, webhook_id) is not None

    async def delete_webhook(self, context: TenantContext, webhook_id: int) -> bool:
        """Delete a webhook"""
        result = await self.ap.persistence_mgr.execute_async(
            scope_statement(
                sqlalchemy.delete(webhook.Webhook).where(webhook.Webhook.id == webhook_id),
                webhook.Webhook,
                context,
            )
        )
        return (result.rowcount or 0) > 0

    async def get_enabled_webhooks(self, context: TenantContext) -> list[dict]:
        """Get all enabled webhooks"""
        result = await self.ap.persistence_mgr.execute_async(
            scope_statement(
                sqlalchemy.select(webhook.Webhook).where(webhook.Webhook.enabled == True),
                webhook.Webhook,
                context,
            )
            .order_by(webhook.Webhook.id)
            .limit(self.max_per_workspace())
        )

        webhooks = result.all()
        return [self.ap.persistence_mgr.serialize_model(webhook.Webhook, wh) for wh in webhooks]
