

from sqlalchemy import func, select, text, update
from sqlalchemy.ext.asyncio import AsyncSession

from src.db.models.org_unit import OrgUnit

from sqlalchemy.orm import joinedload




class OrgUnitRepository:
    def __init__(self, db: AsyncSession):
        self.db = db
    
    async def get_list(
            self, 
            offset: int | None = None, 
            limit: int | None = None,
            is_ssp: bool | None = None,
            is_active: bool | None = None,
            org_unit_id: int | list[int] | None = None,
            with_count: bool = False,
            load_users: bool = False,
    ) -> list[OrgUnit] | tuple[int, list[OrgUnit]]:
        if with_count:
            query = select(func.count().over().label("total_count"), OrgUnit)
        else:
            query = select(OrgUnit)
        where = []
        if is_ssp is not None:
            where.append(OrgUnit.is_ssp == is_ssp)
        if is_active is not None:
            where.append(OrgUnit.is_active == is_active)
        if org_unit_id is not None:
            if isinstance(org_unit_id, int):
                where.append(OrgUnit.id == org_unit_id)
            else:
                where.append(OrgUnit.id.in_(org_unit_id))
        
        query = query.where(*where)
        if load_users:
            query = query.options(
                joinedload(OrgUnit.users)
            )
        
        query = query.order_by(OrgUnit.id)

        if offset is not None:
            query = query.offset(offset)
        if limit is not None:
            query = query.limit(limit)

        if with_count:
            result = (await self.db.execute(query)).unique().all()
            if result:
                return result[0][0], [res[1] for res in result]
            else:
                count_query = select(func.count(OrgUnit.id))
                if query.whereclause is not None:
                    count_query = count_query.where(
                        query.whereclause
                    )
                return (await self.db.execute(count_query)).scalar(), []
        else:
            return (await self.db.execute(query)).scalars().unique().all()
            
    
    async def get(
            self, 
            org_unit_id: int,
            load_users: bool = False
    ) -> OrgUnit | None:
        query = select(OrgUnit).where(OrgUnit.id == org_unit_id)
        if load_users:
            query = query.options(
                joinedload(OrgUnit.users)
            )

        return (await self.db.execute(query)).scalars().first()

    async def create(
            self, 
            title: str,
            is_ssp: bool,
            utc_offset: str,
        ) -> OrgUnit:
        """Создание SSP."""
        ssp = OrgUnit(title=title, is_ssp=is_ssp, utc_offset=utc_offset)
        self.db.add(ssp)
        await self.db.flush()
        # await self.db.refresh(ssp)
        return ssp

    async def update(
        self, org_unit: OrgUnit, **kwargs,
    ) -> OrgUnit | None:
        if not org_unit:
            return None

        old_offset = org_unit.utc_offset
        for field, value in kwargs.items():
            setattr(org_unit, field, value)
        
        await self.db.flush()

        if org_unit.utc_offset != old_offset:
            await self.db.execute(
                text(
                    """
                    SELECT v3.upd_phases_timezones(
                            :org_unit_id,
                            :old_tz,
                            :new_tz
                        )
                    """
                ),
                {
                    "org_unit_id": org_unit.id,
                    "old_tz": old_offset,
                    "new_tz": org_unit.utc_offset,
                },
            )
        # await self.db.refresh(ssp)
        return org_unit

    async def logical_delete(self, org_unit_id: int, is_active: bool | None = None) -> bool:
        """Логическое удаление SSP."""

        query = update(OrgUnit).where(OrgUnit.id == org_unit_id)
        if is_active is not None:
            query = query.where(OrgUnit.is_active == is_active)
        query = query.values(is_active=False)
        res = await self.db.execute(query)
        await self.db.flush()

        return res.rowcount > 0
