"""Campaign application repositories — Phase 7.4."""
from __future__ import annotations

from uuid import UUID

from sqlalchemy import func, select

from app.models.campaigns import CampaignApplication
from app.repositories.base import TenantBaseRepository


class CampaignApplicationRepository(TenantBaseRepository[CampaignApplication]):
    model = CampaignApplication

    async def get_by_idempotency(
        self, tenant_id: UUID, idempotency_key: str | None
    ) -> CampaignApplication | None:
        if not idempotency_key:
            return None
        stmt = select(CampaignApplication).where(
            CampaignApplication.tenant_id == tenant_id,
            CampaignApplication.idempotency_key == idempotency_key,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()

    async def count_for_member(
        self,
        tenant_id: UUID,
        campaign_id: UUID,
        member_id: UUID,
        *,
        exclude_statuses: tuple = (),
    ) -> int:
        clauses = [
            CampaignApplication.tenant_id == tenant_id,
            CampaignApplication.campaign_id == campaign_id,
            CampaignApplication.member_id == member_id,
        ]
        if exclude_statuses:
            clauses.append(CampaignApplication.status.notin_(exclude_statuses))
        stmt = select(func.count()).select_from(CampaignApplication).where(*clauses)
        result = await self.session.execute(stmt)
        return int(result.scalar_one())

    async def list_for_campaign(
        self,
        tenant_id: UUID,
        campaign_id: UUID,
        *,
        offset: int = 0,
        limit: int = 50,
    ):
        stmt = (
            select(CampaignApplication)
            .where(
                CampaignApplication.tenant_id == tenant_id,
                CampaignApplication.campaign_id == campaign_id,
            )
            .order_by(CampaignApplication.created_at.desc())
            .offset(offset)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def count_for_campaign(self, tenant_id: UUID, campaign_id: UUID) -> int:
        stmt = (
            select(func.count())
            .select_from(CampaignApplication)
            .where(
                CampaignApplication.tenant_id == tenant_id,
                CampaignApplication.campaign_id == campaign_id,
            )
        )
        result = await self.session.execute(stmt)
        return int(result.scalar_one())
