"""Sports Center foundation repositories — Phase 9.0."""
from __future__ import annotations

from uuid import UUID

from sqlalchemy import select

from app.models.foundation import (
    AttendanceGateway,
    Branch,
    Coach,
    Court,
    Device,
    DeviceProvider,
    Facility,
    Locker,
    LockerRoom,
    Membership,
    MembershipType,
    Room,
    Sport,
    SportsAuditLog,
    SportsCenter,
    SportsConfiguration,
    SportsEvent,
    SportsPermission,
    SportsRole,
    SportsSetting,
)
from app.repositories.base import TenantBaseRepository


class SportsCenterRepository(TenantBaseRepository[SportsCenter]):
    model = SportsCenter

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


class BranchRepository(TenantBaseRepository[Branch]):
    model = Branch

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

    async def list_by_center(
        self, tenant_id: UUID, sports_center_id: UUID, *, offset: int = 0, limit: int = 50
    ):
        stmt = (
            select(Branch)
            .where(
                Branch.tenant_id == tenant_id,
                Branch.sports_center_id == sports_center_id,
                Branch.is_deleted.is_(False),
            )
            .offset(offset)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class SportRepository(TenantBaseRepository[Sport]):
    model = Sport

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


class MembershipTypeRepository(TenantBaseRepository[MembershipType]):
    model = MembershipType

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


class MembershipRepository(TenantBaseRepository[Membership]):
    model = Membership

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


class CoachRepository(TenantBaseRepository[Coach]):
    model = Coach

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


class SportsRoleRepository(TenantBaseRepository[SportsRole]):
    model = SportsRole

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


class SportsPermissionRepository(TenantBaseRepository[SportsPermission]):
    model = SportsPermission

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


class FacilityRepository(TenantBaseRepository[Facility]):
    model = Facility

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


class CourtRepository(TenantBaseRepository[Court]):
    model = Court

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


class RoomRepository(TenantBaseRepository[Room]):
    model = Room

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


class LockerRoomRepository(TenantBaseRepository[LockerRoom]):
    model = LockerRoom

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


class LockerRepository(TenantBaseRepository[Locker]):
    model = Locker

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


class DeviceProviderRepository(TenantBaseRepository[DeviceProvider]):
    model = DeviceProvider

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


class DeviceRepository(TenantBaseRepository[Device]):
    model = Device

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


class AttendanceGatewayRepository(TenantBaseRepository[AttendanceGateway]):
    model = AttendanceGateway

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


class SportsConfigurationRepository(TenantBaseRepository[SportsConfiguration]):
    model = SportsConfiguration

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


class SportsEventRepository(TenantBaseRepository[SportsEvent]):
    model = SportsEvent

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


class SportsSettingRepository(TenantBaseRepository[SportsSetting]):
    model = SportsSetting

    async def get_by_key(
        self,
        tenant_id: UUID,
        key: str,
        *,
        sports_center_id: UUID | None = None,
        branch_id: UUID | None = None,
    ) -> SportsSetting | None:
        stmt = select(SportsSetting).where(
            SportsSetting.tenant_id == tenant_id,
            SportsSetting.key == key,
            SportsSetting.sports_center_id == sports_center_id,
            SportsSetting.branch_id == branch_id,
            SportsSetting.is_deleted.is_(False),
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class SportsAuditLogRepository(TenantBaseRepository[SportsAuditLog]):
    model = SportsAuditLog

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