"""Nexus — SyncLog Repository (Async SQLAlchemy implementation)"""

from typing import Optional, List, Tuple
from sqlalchemy import select, func
from sqlalchemy.ext.asyncio import AsyncSession

from server.domain.models import SyncLog, Server


class SyncLogRepositoryImpl:
    """Async SQLAlchemy implementation of SyncLog data access"""

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

    async def get_by_server_id(self, server_id: int, limit: int = 50) -> List[SyncLog]:
        result = await self.session.execute(
            select(SyncLog)
            .where(SyncLog.server_id == server_id)
            .order_by(SyncLog.started_at.desc())
            .limit(limit)
        )
        return list(result.scalars().all())

    async def get_all_paginated(
        self,
        server_id: Optional[int] = None,
        status: Optional[str] = None,
        sync_mode: Optional[str] = None,
        trigger_type: Optional[str] = None,
        offset: int = 0,
        limit: int = 50,
    ) -> Tuple[list, int]:
        """Global sync log list with filters + server name join + total count."""
        filters = []
        if server_id:
            filters.append(SyncLog.server_id == server_id)
        if status:
            filters.append(SyncLog.status == status)
        if sync_mode:
            filters.append(SyncLog.sync_mode == sync_mode)
        if trigger_type:
            filters.append(SyncLog.trigger_type == trigger_type)

        # Count
        count_stmt = select(func.count(SyncLog.id))
        if filters:
            count_stmt = count_stmt.where(*filters)
        total = int((await self.session.execute(count_stmt)).scalar() or 0)

        # Data (with server name join)
        data_stmt = (
            select(SyncLog, Server.name.label("server_name"))
            .join(Server, SyncLog.server_id == Server.id, isouter=True)
            .order_by(SyncLog.started_at.desc())
            .offset(offset)
            .limit(limit)
        )
        if filters:
            data_stmt = data_stmt.where(*filters)
        rows = (await self.session.execute(data_stmt)).all()
        return rows, total

    async def create(self, log: SyncLog) -> SyncLog:
        self.session.add(log)
        await self.session.commit()
        return log

    # Allowed fields for update_status — prevents arbitrary field injection via **kwargs
    SYNC_LOG_UPDATABLE_FIELDS = {"finished_at", "duration_seconds", "error_message", "diff_summary", "status"}

    async def update_status(self, id: int, status: str, **kwargs) -> Optional[SyncLog]:
        log = await self.session.get(SyncLog, id)
        if log:
            log.status = status
            for key, value in kwargs.items():
                if key in self.SYNC_LOG_UPDATABLE_FIELDS:
                    setattr(log, key, value)
            await self.session.commit()
        return log