from __future__ import annotations

from typing import Any, Optional
from uuid import UUID

from src.core.exceptions import NotFoundError, ValidationError
from src.core.security.encryption import encrypt_value
from src.domain.integration_events.catalog import STANDARD_EVENTS
from src.domain.integration_events.models import IntegrationSubscription
from src.domain.integration_events.repository import IntegrationEventsRepository
from src.domain.integration_events.schemas import (
    EventRegistryItem,
    IntegrationSubscriptionResponse,
    UpsertSubscriptionRequest,
)
from src.integrations.cloud_control_client import CloudControlClient


def _to_response(row: IntegrationSubscription) -> IntegrationSubscriptionResponse:
    return IntegrationSubscriptionResponse(
        id=row.id,
        workspace_id=row.workspace_id,
        project_id=row.project_id,
        connection_id=row.connection_id,
        event=row.event,
        event_version=row.event_version,
        destination=row.destination,
        url=row.url,
        secret_configured=bool(row.secret_enc),
        filter_json=row.filter_json or {},
        ignore_origin=row.ignore_origin,
        max_hops=row.max_hops,
        status=row.status,
        created_at=row.created_at,
        updated_at=row.updated_at,
    )


class IntegrationEventsService:
    def __init__(self, *, repo: IntegrationEventsRepository, cloud: CloudControlClient) -> None:
        self._repo = repo
        self._cloud = cloud

    def list_registry(self, custom: list[dict[str, Any]] | None = None) -> list[EventRegistryItem]:
        rows = list(STANDARD_EVENTS) + (custom or [])
        return [EventRegistryItem.model_validate(r) for r in rows]

    async def list_subscriptions(self, project_id: UUID) -> list[IntegrationSubscriptionResponse]:
        rows = await self._repo.list_subscriptions(project_id)
        return [_to_response(r) for r in rows]

    async def create_subscription(
        self,
        *,
        workspace_id: UUID,
        project_id: UUID,
        body: UpsertSubscriptionRequest,
    ) -> IntegrationSubscriptionResponse:
        dest = body.destination.strip().lower()
        if dest not in {"webhook", "slack", "make_com", "n8n", "zapier"}:
            raise ValidationError("Unsupported destination")
        if dest == "webhook" and not (body.url or "").strip():
            raise ValidationError("url is required for webhook destinations")
        secret_enc: Optional[str] = None
        if body.secret:
            secret_enc = encrypt_value(body.secret)
        row = IntegrationSubscription(
            workspace_id=workspace_id,
            project_id=project_id,
            connection_id=body.connection_id,
            event=body.event.strip(),
            event_version=body.event_version,
            destination=dest,
            url=(body.url or "").strip() or None,
            secret_enc=secret_enc,
            filter_json=body.filter_json or {},
            ignore_origin=body.ignore_origin,
            max_hops=max(1, min(body.max_hops, 20)),
            status=body.status if body.status in {"active", "paused", "disabled"} else "active",
        )
        await self._repo.add_subscription(row)
        await self._sync_cloud(row, body.secret)
        return _to_response(row)

    async def delete_subscription(self, project_id: UUID, sub_id: UUID) -> None:
        row = await self._repo.get_subscription(project_id, sub_id)
        if not row:
            raise NotFoundError("Subscription not found")
        await self._cloud.delete_event_subscription(str(row.id), str(project_id))
        await self._repo.delete_subscription(row)

    async def _sync_cloud(self, row: IntegrationSubscription, secret: Optional[str]) -> None:
        await self._cloud.upsert_event_subscription(
            subscription_id=str(row.id),
            workspace_id=str(row.workspace_id),
            project_id=str(row.project_id),
            connection_id=str(row.connection_id) if row.connection_id else None,
            event=row.event,
            event_version=row.event_version,
            destination=row.destination,
            url=row.url,
            filter_json=row.filter_json or {},
            ignore_origin=row.ignore_origin,
            max_hops=row.max_hops,
            status=row.status,
            signing_secret=secret,
        )
