package dev.lions.unionflow.server.service.mutuelle;

import dev.lions.unionflow.server.api.dto.mutuelle.financier.ParametresFinanciersMutuellRequest;
import dev.lions.unionflow.server.api.dto.mutuelle.financier.ParametresFinanciersMutuellResponse;
import dev.lions.unionflow.server.entity.Organisation;
import dev.lions.unionflow.server.entity.mutuelle.ParametresFinanciersMutuelle;
import dev.lions.unionflow.server.repository.OrganisationRepository;
import dev.lions.unionflow.server.repository.mutuelle.ParametresFinanciersMutuellRepository;
import io.quarkus.test.InjectMock;
import io.quarkus.test.junit.QuarkusTest;
import jakarta.inject.Inject;
import jakarta.ws.rs.NotFoundException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;
import java.util.Optional;
import java.util.UUID;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@QuarkusTest
@DisplayName("ParametresFinanciersService")
class ParametresFinanciersServiceTest {

    @Inject ParametresFinanciersService service;
    @InjectMock ParametresFinanciersMutuellRepository repo;
    @InjectMock OrganisationRepository organisationRepository;

    @Test
    @DisplayName("getByOrganisation — lève NotFoundException si absent")
    void getByOrganisation_absent_leveException() {
        UUID orgId = UUID.randomUUID();
        when(repo.findByOrganisation(orgId)).thenReturn(Optional.empty());
        assertThatThrownBy(() -> service.getByOrganisation(orgId))
                .isInstanceOf(NotFoundException.class);
    }

    @Test
    @DisplayName("creerOuMettrAJour — crée les paramètres si inexistants")
    void creerOuMettrAJour_inexistants_créeSansErreur() {
        UUID orgId = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(orgId);
        org.setNom("Mutuelle Test");

        ParametresFinanciersMutuellRequest req = ParametresFinanciersMutuellRequest.builder()
                .organisationId(orgId.toString())
                .valeurNominaleParDefaut(new BigDecimal("5000"))
                .tauxInteretAnnuelEpargne(new BigDecimal("0.03"))
                .tauxDividendePartsAnnuel(new BigDecimal("0.05"))
                .periodiciteCalcul("MENSUEL")
                .seuilMinEpargneInterets(BigDecimal.ZERO)
                .build();

        when(organisationRepository.findByIdOptional(orgId)).thenReturn(Optional.of(org));
        when(repo.findByOrganisation(orgId)).thenReturn(Optional.empty());
        // any(ParametresFinanciersMutuelle.class) resolves persist(Entity) unambiguously
        doNothing().when(repo).persist(any(ParametresFinanciersMutuelle.class));

        ParametresFinanciersMutuellResponse resp = service.creerOuMettrAJour(req);

        assertThat(resp).isNotNull();
        verify(repo).persist(argThat((ParametresFinanciersMutuelle p) ->
                p.getTauxInteretAnnuelEpargne().compareTo(new BigDecimal("0.03")) == 0
                && p.getPeriodiciteCalcul().equals("MENSUEL")));
    }

    @Test
    @DisplayName("creerOuMettrAJour — la périodicité est normalisée en majuscules")
    void creerOuMettrAJour_periodiciteMajuscules() {
        UUID orgId = UUID.randomUUID();
        Organisation org = new Organisation();
        org.setId(orgId);
        org.setNom("Test");

        ParametresFinanciersMutuellRequest req = ParametresFinanciersMutuellRequest.builder()
                .organisationId(orgId.toString())
                .valeurNominaleParDefaut(new BigDecimal("5000"))
                .tauxInteretAnnuelEpargne(BigDecimal.ZERO)
                .tauxDividendePartsAnnuel(BigDecimal.ZERO)
                .periodiciteCalcul("trimestriel")
                .build();

        when(organisationRepository.findByIdOptional(orgId)).thenReturn(Optional.of(org));
        when(repo.findByOrganisation(orgId)).thenReturn(Optional.empty());
        doNothing().when(repo).persist(any(ParametresFinanciersMutuelle.class));

        service.creerOuMettrAJour(req);

        verify(repo).persist(argThat((ParametresFinanciersMutuelle p) ->
                p.getPeriodiciteCalcul().equals("TRIMESTRIEL")));
    }
}
