"""Delivery foundation repositories."""
from __future__ import annotations

from typing import Sequence
from uuid import UUID

from sqlalchemy import select

from app.models.foundation import (
    DeliveryAuditLog,
    DeliveryConfiguration,
    DeliveryHub,
    DeliveryOrganization,
    DeliveryPermission,
    DeliveryRole,
    DeliverySetting,
    ExternalProviderConfig,
    RoutingEngineRegistration,
)
from app.repositories.base import TenantBaseRepository


class DeliveryOrganizationRepository(TenantBaseRepository[DeliveryOrganization]):
    model = DeliveryOrganization

    async def get_by_code(
        self, tenant_id: UUID, code: str
    ) -> DeliveryOrganization | None:
        stmt = select(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.code == code,
            self.model.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class DeliveryHubRepository(TenantBaseRepository[DeliveryHub]):
    model = DeliveryHub

    async def list_by_organization(
        self, tenant_id: UUID, organization_id: UUID, *, offset: int = 0, limit: int = 20
    ) -> Sequence[DeliveryHub]:
        stmt = (
            select(self.model)
            .where(
                self.model.tenant_id == tenant_id,
                self.model.organization_id == organization_id,
                self.model.is_deleted.is_(False),
            )
            .offset(offset)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class DeliveryRoleRepository(TenantBaseRepository[DeliveryRole]):
    model = DeliveryRole


class DeliveryPermissionRepository(TenantBaseRepository[DeliveryPermission]):
    model = DeliveryPermission


class ExternalProviderConfigRepository(TenantBaseRepository[ExternalProviderConfig]):
    model = ExternalProviderConfig

    async def get_by_code(
        self, tenant_id: UUID, code: str
    ) -> ExternalProviderConfig | None:
        stmt = select(self.model).where(
            self.model.tenant_id == tenant_id,
            self.model.code == code,
            self.model.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class RoutingEngineRegistrationRepository(
    TenantBaseRepository[RoutingEngineRegistration]
):
    model = RoutingEngineRegistration


class DeliveryConfigurationRepository(TenantBaseRepository[DeliveryConfiguration]):
    model = DeliveryConfiguration


class DeliverySettingRepository(TenantBaseRepository[DeliverySetting]):
    model = DeliverySetting

    async def get_by_key(
        self,
        tenant_id: UUID,
        key: str,
        *,
        organization_id: UUID | None = None,
        hub_id: UUID | None = None,
    ) -> DeliverySetting | None:
        clauses = [
            self.model.tenant_id == tenant_id,
            self.model.key == key,
            self.model.is_deleted.is_(False),
        ]
        if organization_id is None:
            clauses.append(self.model.organization_id.is_(None))
        else:
            clauses.append(self.model.organization_id == organization_id)
        if hub_id is None:
            clauses.append(self.model.hub_id.is_(None))
        else:
            clauses.append(self.model.hub_id == hub_id)
        stmt = select(self.model).where(*clauses)
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class DeliveryAuditLogRepository(TenantBaseRepository[DeliveryAuditLog]):
    model = DeliveryAuditLog

    async def list_for_entity(
        self,
        tenant_id: UUID,
        entity_type: str,
        entity_id: UUID,
        *,
        limit: int = 100,
    ) -> Sequence[DeliveryAuditLog]:
        stmt = (
            select(self.model)
            .where(
                self.model.tenant_id == tenant_id,
                self.model.entity_type == entity_type,
                self.model.entity_id == entity_id,
            )
            .order_by(self.model.created_at.desc())
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()
