from typing import Optional
from uuid import UUID

from sqlalchemy import func, select, and_
from sqlalchemy.ext.asyncio import AsyncSession

from src.apps.sections.models.section import Section
from src.core.exceptions import ConflictError, NotFoundError


class SectionService:
    def __init__(self, db: AsyncSession):
        self.db = db

    async def list_sections(
        self,
        tenant_id: UUID,
        skip: int = 0,
        limit: int = 50,
    ) -> tuple[list, int]:
        conditions = [Section.tenant_id == tenant_id]

        count_q = await self.db.execute(
            select(func.count(Section.id)).where(and_(*conditions))
        )
        total = count_q.scalar_one()

        result = await self.db.execute(
            select(Section)
            .where(and_(*conditions))
            .order_by(Section.code.asc())
            .offset(skip)
            .limit(limit)
        )
        return result.scalars().all(), total

    async def get_by_id(
        self, section_id: UUID, tenant_id: UUID
    ) -> Optional[Section]:
        result = await self.db.execute(
            select(Section).where(
                and_(
                    Section.id == section_id,
                    Section.tenant_id == tenant_id,
                )
            )
        )
        return result.scalar_one_or_none()

    async def create(self, tenant_id: UUID, data: dict) -> Section:
        # Enforce code uniqueness per tenant
        existing = await self.db.execute(
            select(Section).where(
                and_(
                    Section.tenant_id == tenant_id,
                    Section.code == data["code"],
                )
            )
        )
        if existing.scalar_one_or_none():
            raise ConflictError(
                f"A section with code '{data['code']}' already exists in this cemetery"
            )

        section = Section(
            tenant_id=tenant_id,
            code=data["code"],
            name=data["name"],
            description=data.get("description"),
            is_religious=data.get("is_religious", False),
            religious_denomination=data.get("religious_denomination"),
        )
        self.db.add(section)
        await self.db.flush()
        return section

    async def update(
        self, section_id: UUID, tenant_id: UUID, data: dict
    ) -> Section:
        section = await self.get_by_id(section_id, tenant_id)
        if not section:
            raise NotFoundError("Section not found")

        for field, value in data.items():
            if hasattr(section, field):
                setattr(section, field, value)

        await self.db.flush()
        return section

    async def delete(self, section_id: UUID, tenant_id: UUID) -> None:
        section = await self.get_by_id(section_id, tenant_id)
        if not section:
            raise NotFoundError("Section not found")

        await self.db.delete(section)
        await self.db.flush()
