"""Posting repositories."""
from __future__ import annotations

from uuid import UUID

from sqlalchemy import select
from sqlalchemy.orm import selectinload

from app.models.posting import (
    AccountingAuditLog,
    JournalEntry,
    PostingError,
    PostingLog,
    PostingReference,
    Voucher,
    VoucherLine,
)
from app.models.types import VoucherStatus
from app.repositories.base import TenantBaseRepository


class VoucherRepository(TenantBaseRepository[Voucher]):
    model = Voucher

    async def get_with_lines(self, tenant_id: UUID, voucher_id: UUID) -> Voucher | None:
        stmt = (
            select(Voucher)
            .options(selectinload(Voucher.lines))
            .where(Voucher.tenant_id == tenant_id, Voucher.id == voucher_id)
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()

    async def get_by_number(self, tenant_id: UUID, voucher_number: str) -> Voucher | None:
        stmt = select(Voucher).where(
            Voucher.tenant_id == tenant_id, Voucher.voucher_number == voucher_number
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()

    async def list_by_status(self, tenant_id: UUID, status: VoucherStatus, *, limit: int = 50):
        stmt = (
            select(Voucher)
            .where(Voucher.tenant_id == tenant_id, Voucher.status == status)
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class VoucherLineRepository(TenantBaseRepository[VoucherLine]):
    model = VoucherLine


class JournalEntryRepository(TenantBaseRepository[JournalEntry]):
    model = JournalEntry

    async def list_by_voucher(self, tenant_id: UUID, voucher_id: UUID):
        stmt = select(JournalEntry).where(
            JournalEntry.tenant_id == tenant_id,
            JournalEntry.voucher_id == voucher_id,
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()

    async def list_by_account(self, tenant_id: UUID, account_id: UUID, *, limit: int = 100):
        stmt = (
            select(JournalEntry)
            .where(
                JournalEntry.tenant_id == tenant_id,
                JournalEntry.account_id == account_id,
            )
            .limit(limit)
        )
        result = await self.session.execute(stmt)
        return result.scalars().all()


class PostingLogRepository(TenantBaseRepository[PostingLog]):
    model = PostingLog


class PostingErrorRepository(TenantBaseRepository[PostingError]):
    model = PostingError


class PostingReferenceRepository(TenantBaseRepository[PostingReference]):
    model = PostingReference

    async def get_by_source(
        self,
        tenant_id: UUID,
        source_module: str,
        source_document_type: str,
        source_document_id: str,
    ) -> PostingReference | None:
        stmt = select(PostingReference).where(
            PostingReference.tenant_id == tenant_id,
            PostingReference.source_module == source_module,
            PostingReference.source_document_type == source_document_type,
            PostingReference.source_document_id == source_document_id,
        )
        result = await self.session.execute(stmt)
        return result.scalar_one_or_none()


class AuditLogRepository(TenantBaseRepository[AccountingAuditLog]):
    model = AccountingAuditLog
