from datetime import datetime, timezone
from typing import List

from sqlalchemy.orm import Session

from src.domain.entities.legal_charges import LegalChargesRule
from src.domain.interfaces.legal_charges_repository import LegalChargesRepositoryInterface
from src.infrastructure.models.legal_charges_model import LegalChargesModel


def _to_entity(model: LegalChargesModel) -> LegalChargesRule:
    return LegalChargesRule(
        id=model.id,
        category_id=model.category_id,
        condition=model.condition or "",
        net_loan_amount=model.net_loan_amount or 0,
        legal_charges=model.legal_charges or 0,
    )


class SqlLegalChargesRepository(LegalChargesRepositoryInterface):
    """SQLAlchemy implementation of LegalChargesRepositoryInterface."""

    def __init__(self, db: Session) -> None:
        self.db = db

    def list_all(self) -> List[LegalChargesRule]:
        rows = self.db.query(LegalChargesModel).all()
        return [_to_entity(r) for r in rows]

    def upsert_all(
        self,
        rules: List[LegalChargesRule],
        user_id: int,
    ) -> List[LegalChargesRule]:
        now = datetime.now(timezone.utc)
        result: List[LegalChargesRule] = []

        for rule in rules:
            # Delete existing record(s) for this category — mirrors Laravel's
            # delete-then-insert pattern
            self.db.query(LegalChargesModel).filter(
                LegalChargesModel.category_id == rule.category_id
            ).delete(synchronize_session=False)

            new_row = LegalChargesModel(
                category_id=rule.category_id,
                condition=rule.condition,
                net_loan_amount=rule.net_loan_amount,
                legal_charges=rule.legal_charges,
                created_by=user_id,
                updated_by=user_id,
                created_at=now,
                updated_at=now,
            )
            self.db.add(new_row)
            self.db.flush()   # populate new_row.id before converting
            result.append(_to_entity(new_row))

        self.db.commit()
        return result
