from typing import Annotated

from fastapi import Depends
from sqlalchemy import select
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.ext.asyncio import AsyncSession

from src.core.db import SessionDep
from src.group_settings.models import GroupConfig, LogEntry


class GroupConfigRepo:
    def __init__(self, session: AsyncSession):
        self.session = session

    async def get_all(self) -> list[GroupConfig]:
        result = await self.session.execute(select(GroupConfig))
        return list(result.scalars().all())

    async def get_by_group_email(self, group_email: str) -> GroupConfig | None:
        result = await self.session.execute(
            select(GroupConfig).where(GroupConfig.group_email == group_email)
        )
        return result.scalar_one_or_none()

    async def upsert(
        self,
        group_email: str,
        **kwargs,
    ) -> GroupConfig:
        """Insert or update a GroupConfig row.
        Only non-None fields in kwargs are written.
        """
        config = await self.get_by_group_email(group_email)
        if not config:
            config = GroupConfig(group_email=group_email)
            self.session.add(config)

        for key, value in kwargs.items():
            if value is not None and hasattr(config, key):
                setattr(config, key, value)

        await self.session.commit()
        await self.session.refresh(config)
        return config

    async def create_empty(self, group_email: str) -> GroupConfig:
        """Register a new group with no credentials yet (super-admin action)."""
        stmt = (
            insert(GroupConfig)
            .values(group_email=group_email)
            .on_conflict_do_nothing()
            .returning(GroupConfig)
        )
        result = await self.session.execute(stmt)
        row = result.scalar_one_or_none()
        await self.session.commit()
        if row is None:
            # already existed — fetch it
            row = await self.get_by_group_email(group_email)
        return row  # type: ignore[return-value]

    async def delete(self, group_email: str) -> bool:
        config = await self.get_by_group_email(group_email)
        if config is None:
            return False
        await self.session.delete(config)
        await self.session.commit()
        return True

    async def get_logs(self, group_email: str, limit: int = 100) -> list[LogEntry]:
        """Fetch the most recent audit logs for a group."""
        result = await self.session.execute(
            select(LogEntry)
            .where(LogEntry.group_email == group_email)
            .order_by(LogEntry.timestamp.desc())
            .limit(limit)
        )
        return list(result.scalars().all())


def get_group_config_repo(session: SessionDep) -> GroupConfigRepo:
    return GroupConfigRepo(session)


GroupConfigRepoDep = Annotated[GroupConfigRepo, Depends(get_group_config_repo)]
