from typing import List

from fastapi import APIRouter, Depends, HTTPException, status
from pydantic import BaseModel
from sqlalchemy.orm import Session

from src.infrastructure.database.connection import get_db
from src.infrastructure.repositories.sql_legal_charges_repository import SqlLegalChargesRepository
from src.application.use_cases.legal_charges.list_legal_charges import ListLegalChargesUseCase
from src.application.use_cases.legal_charges.save_legal_charges import SaveLegalChargesUseCase
from src.domain.entities.legal_charges import LegalChargesRule
from src.core.rbac.rbac_dependency import require_permission, get_current_user_payload
from src.core.rbac.permissions_registry import Perm
from src.core.exceptions import ValidationError

router = APIRouter()


# ── Schemas ────────────────────────────────────────────────────────────────────

class LegalChargesRuleResponse(BaseModel):
    category_id: int
    condition: str
    net_loan_amount: int
    legal_charges: int


class LegalChargesRuleRequest(BaseModel):
    category_id: int
    condition: str
    net_loan_amount: int
    legal_charges: int


# ── Endpoints ──────────────────────────────────────────────────────────────────

@router.get(
    "/",
    response_model=List[LegalChargesRuleResponse],
    tags=["legal-charges"],
    dependencies=[Depends(require_permission(Perm.MERCHANTS_VIEW))],
)
def list_legal_charges(db: Session = Depends(get_db)):
    """Return all legal-charges rules (one per merchant category that has a rule)."""
    repo = SqlLegalChargesRepository(db)
    rules = ListLegalChargesUseCase(repo).execute()
    return [
        LegalChargesRuleResponse(
            category_id=r.category_id,
            condition=r.condition,
            net_loan_amount=r.net_loan_amount,
            legal_charges=r.legal_charges,
        )
        for r in rules
    ]


@router.put(
    "/",
    response_model=List[LegalChargesRuleResponse],
    tags=["legal-charges"],
    dependencies=[Depends(require_permission(Perm.MERCHANTS_EDIT))],
)
def save_legal_charges(
    body: List[LegalChargesRuleRequest],
    db: Session = Depends(get_db),
    payload: dict = Depends(get_current_user_payload),
):
    """Upsert legal-charges rules for a list of merchant categories.

    For each category in the request the existing rule (if any) is replaced.
    Categories not included in the request are left untouched.
    Mirrors Laravel's Dashboard::saveLegalCharges().
    """
    user_id: int = payload.get("user_id", 0)
    repo = SqlLegalChargesRepository(db)
    rules = [
        LegalChargesRule(
            category_id=item.category_id,
            condition=item.condition,
            net_loan_amount=item.net_loan_amount,
            legal_charges=item.legal_charges,
        )
        for item in body
    ]
    try:
        saved = SaveLegalChargesUseCase(repo).execute(rules=rules, user_id=user_id)
    except ValidationError as exc:
        raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(exc))

    return [
        LegalChargesRuleResponse(
            category_id=r.category_id,
            condition=r.condition,
            net_loan_amount=r.net_loan_amount,
            legal_charges=r.legal_charges,
        )
        for r in saved
    ]
