package io.gmss.fiscad.implementations.rfu.metier;

import io.gmss.fiscad.entities.decoupage.Arrondissement;
import io.gmss.fiscad.entities.infocad.metier.Enquete;
import io.gmss.fiscad.entities.infocad.metier.Parcelle;
import io.gmss.fiscad.entities.rfu.metier.DonneesImpositionTfu;
import io.gmss.fiscad.entities.rfu.metier.ImpositionsTfu;
import io.gmss.fiscad.entities.rfu.parametre.BaremRfuNonBati;
import io.gmss.fiscad.entities.rfu.parametre.Exercice;
import io.gmss.fiscad.exceptions.BadRequestException;
import io.gmss.fiscad.exceptions.NotFoundException;
import io.gmss.fiscad.interfaces.rfu.metier.DonneesImpositionTfuService;
import io.gmss.fiscad.paylaods.response.DonneesImpositionTfuResponse;
import io.gmss.fiscad.repositories.decoupage.ArrondissementRepository;
import io.gmss.fiscad.repositories.infocad.metier.EnqueteRepository;
import io.gmss.fiscad.repositories.infocad.metier.ParcelleRepository;
import io.gmss.fiscad.repositories.rfu.metier.DonneesImpositionTfuRepository;
import io.gmss.fiscad.repositories.rfu.metier.ImpositionsTfuRepository;
import io.gmss.fiscad.repositories.rfu.parametre.BaremRfuNonBatiRepository;
import io.gmss.fiscad.repositories.rfu.parametre.ExerciceRepository;
import jakarta.transaction.Transactional;
import lombok.AllArgsConstructor;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
@AllArgsConstructor
public class DonneesImpositionTfuServiceImpl implements DonneesImpositionTfuService {

    private final DonneesImpositionTfuRepository donneesImpositionTfuRepository;
    private final ParcelleRepository parcelleRepository;
    private final EnqueteRepository enqueteRepository;
    private final ImpositionsTfuRepository impositionsTfuRepository;
    private final BaremRfuNonBatiRepository baremRfuNonBatiRepository;
    private final ExerciceRepository exerciceRepository;
    private final ArrondissementRepository arrondissementRepository;



    @Override
    public DonneesImpositionTfu createDonneesImpositionTfu(DonneesImpositionTfu donneesImpositionTfu) throws BadRequestException {
        if (donneesImpositionTfu.getId() != null) {
            throw new BadRequestException("Impossible de créer un nouveau donneesImpositionTfu ayant un id non null.");
        }
        return donneesImpositionTfuRepository.save(donneesImpositionTfu);
    }

    @Override
    public DonneesImpositionTfu updateDonneesImpositionTfu(Long id, DonneesImpositionTfu donneesImpositionTfu) throws NotFoundException {
        if (donneesImpositionTfu.getId() == null) {
            throw new BadRequestException("Impossible de mettre à jour un nouveau donneesImpositionTfu ayant un id null.");
        }
        if (!donneesImpositionTfuRepository.existsById(donneesImpositionTfu.getId())) {
            throw new NotFoundException("Impossible de trouver le donneesImpositionTfu spécifié dans notre base de données.");
        }
        return donneesImpositionTfuRepository.save(donneesImpositionTfu);
    }

    @Override
    public void deleteDonneesImpositionTfu(Long id) throws NotFoundException {
        Optional<DonneesImpositionTfu> donneesImpositionTfuOptional = donneesImpositionTfuRepository.findById(id);
        if (donneesImpositionTfuOptional.isPresent()) {
            donneesImpositionTfuRepository.deleteById(donneesImpositionTfuOptional.get().getId());
        } else {
            throw new NotFoundException("Impossible de trouver le donneesImpositionTfu spécifié dans notre base de données.");
        }
    }

    @Override
    public Page<DonneesImpositionTfu> getDonneesImpositionTfuList(Pageable pageable) {
        return donneesImpositionTfuRepository.findAll(pageable);
    }

    @Override
    public List<DonneesImpositionTfu> getDonneesImpositionTfuList() {
        return donneesImpositionTfuRepository.findAll();
    }


    @Override
    public Optional<DonneesImpositionTfu> getDonneesImpositionTfuById(Long id) {
        if (donneesImpositionTfuRepository.existsById(id)) {
            return donneesImpositionTfuRepository.findById(id);
        } else {
            throw new NotFoundException("Impossible de trouver la caractéristique spécifiée dans la base de données.");
        }

    }

    @Override
    @Transactional
    public Long genererDonneesFiscales(ImpositionsTfu impositionsTfu) {
        List<DonneesImpositionTfuResponse> donneesImpositionTfuResponses= donneesImpositionTfuRepository.findAllDonneesImpositionTfu(impositionsTfu.getCommune().getId(),impositionsTfu.getExercice().getAnnee());
        Long n=0l;
        for (DonneesImpositionTfuResponse donneesImpositionTfuResponse: donneesImpositionTfuResponses){
            DonneesImpositionTfu donneesImpositionTfu=new DonneesImpositionTfu();
            donneesImpositionTfu.setImpositionsTfu(impositionsTfu);
            donneesImpositionTfu.setZoneRfuId(donneesImpositionTfuResponse.getZoneRfuId());
            donneesImpositionTfu.setCodeQuartierVillage(donneesImpositionTfuResponse.getCodeQuartierVillage());
            donneesImpositionTfu.setNomQuartierVillage(donneesImpositionTfuResponse.getNomQuartierVillage());
            donneesImpositionTfu.setCodeArrondissement(donneesImpositionTfuResponse.getCodeArrondissement());
            donneesImpositionTfu.setNomArrondissement(donneesImpositionTfuResponse.getNomArrondissement());
            donneesImpositionTfu.setCodeCommune(donneesImpositionTfuResponse.getCodeCommune());
            donneesImpositionTfu.setNomCommune(donneesImpositionTfuResponse.getNomCommune());
            donneesImpositionTfu.setCodeDepartement(donneesImpositionTfuResponse.getCodeDepartement());
            donneesImpositionTfu.setNomDepartement(donneesImpositionTfuResponse.getNomDepartement());
            donneesImpositionTfu.setQ(donneesImpositionTfuResponse.getQ());
            donneesImpositionTfu.setIlot(donneesImpositionTfuResponse.getIlot());
            donneesImpositionTfu.setParcelle(donneesImpositionTfuResponse.getParcelle());
            donneesImpositionTfu.setLatitude(donneesImpositionTfuResponse.getLatitude());
            donneesImpositionTfu.setLongitude(donneesImpositionTfuResponse.getLongitude());
            donneesImpositionTfu.setNup(donneesImpositionTfuResponse.getNup());
            donneesImpositionTfu.setNupProvisoire(donneesImpositionTfuResponse.getNupProvisoire());
            donneesImpositionTfu.setSuperficieParc(donneesImpositionTfuResponse.getSuperficieParc());
            donneesImpositionTfu.setAdresseProp(donneesImpositionTfuResponse.getAdresseProp());
            donneesImpositionTfu.setAnnee(donneesImpositionTfuResponse.getAnnee());
            donneesImpositionTfu.setAdresseSc(donneesImpositionTfuResponse.getAdresseSc());
            donneesImpositionTfu.setBatieOuiNon(donneesImpositionTfuResponse.getBatieOuiNon());
            donneesImpositionTfu.setTfuMinimum(donneesImpositionTfuResponse.getTfuMinimum());
            donneesImpositionTfu.setCategorieBat(donneesImpositionTfuResponse.getCategorieBat());
            donneesImpositionTfu.setDateEnquete(donneesImpositionTfuResponse.getDateEnquete());
            donneesImpositionTfu.setEmailProp(donneesImpositionTfuResponse.getEmailProp());
            donneesImpositionTfu.setEmailSc(donneesImpositionTfuResponse.getEmailSc());
            donneesImpositionTfu.setMontantLoyerAnnuel(donneesImpositionTfuResponse.getMontantLoyerAnnuel());
            donneesImpositionTfu.setEnqueteId(donneesImpositionTfuResponse.getEnqueteId());
            donneesImpositionTfu.setExhonereOuiNon(donneesImpositionTfuResponse.getExhonereOuiNon());
            donneesImpositionTfu.setIfu(donneesImpositionTfuResponse.getIfu());
            donneesImpositionTfu.setNombreBat(donneesImpositionTfuResponse.getNombreBat());
            donneesImpositionTfu.setNombrePiscine(donneesImpositionTfuResponse.getNombrePiscine());
            donneesImpositionTfu.setNombreUlog(donneesImpositionTfuResponse.getNombreUlog());
            donneesImpositionTfu.setNomProp(donneesImpositionTfuResponse.getNomProp());
            donneesImpositionTfu.setNomSc(donneesImpositionTfuResponse.getNomSc());
            donneesImpositionTfu.setNpi(donneesImpositionTfuResponse.getNpi());
            donneesImpositionTfu.setNumBatiment(donneesImpositionTfuResponse.getNumBatiment()==null?"":donneesImpositionTfuResponse.getNumBatiment());
            donneesImpositionTfu.setNumUniteLogement(donneesImpositionTfuResponse.getNumUniteLogement()==null?"":donneesImpositionTfuResponse.getNumUniteLogement());
            donneesImpositionTfu.setPrenomProp(donneesImpositionTfuResponse.getPrenomProp());
            donneesImpositionTfu.setPrenomSc(donneesImpositionTfuResponse.getPrenomSc());
            donneesImpositionTfu.setRaisonSociale(donneesImpositionTfuResponse.getRaisonSociale());
            donneesImpositionTfu.setSecteurId(donneesImpositionTfuResponse.getSecteurId());
            donneesImpositionTfu.setStandingBat(donneesImpositionTfuResponse.getStandingBat());
            donneesImpositionTfu.setStructureId(donneesImpositionTfuResponse.getStructureId());
            donneesImpositionTfu.setSuperficieAuSolBat(donneesImpositionTfuResponse.getSuperficieAuSolBat());
            donneesImpositionTfu.setSuperficieAuSolUlog(donneesImpositionTfuResponse.getSuperficieAuSolUlog());
            donneesImpositionTfu.setTelProp(donneesImpositionTfuResponse.getTelProp());
            donneesImpositionTfu.setTelSc(donneesImpositionTfuResponse.getTelSc());
            donneesImpositionTfu.setTfuMetreCarre(donneesImpositionTfuResponse.getTfuMetreCarre());
            donneesImpositionTfu.setTitreFoncier(donneesImpositionTfuResponse.getTitreFoncier());
            donneesImpositionTfu.setValeurLocativeAdm(donneesImpositionTfuResponse.getValeurLocativeAdm());
            donneesImpositionTfu.setBatimentExhonereOuiNon(donneesImpositionTfuResponse.getBatimentExhonereOuiNon());
            donneesImpositionTfu.setUniteLogementExhonereOuiNon(donneesImpositionTfuResponse.getUniteLogementExhonereOuiNon());
            try {
                Optional<BaremRfuNonBati> baremRfuNonBatiOptional=baremRfuNonBatiRepository.findAllByCommune_IdAndZoneRfu_Id(impositionsTfu.getCommune().getId(),donneesImpositionTfu.getZoneRfuId());
                 if(baremRfuNonBatiOptional.isPresent()){
                     donneesImpositionTfu.setValeurAdministrativeParcelleNonBati(baremRfuNonBatiOptional.get().getValeurAdministrative());
                     donneesImpositionTfu.setTauxParcelleNonBati(baremRfuNonBatiOptional.get().getTaux());
                 }


                donneesImpositionTfuRepository.save(donneesImpositionTfu);
                n++;
            }catch (DataIntegrityViolationException e) {
                if (e.getCause() instanceof org.hibernate.exception.ConstraintViolationException constraintEx &&
                        constraintEx.getSQLException().getSQLState().equals("23505")) {
                    System.out.println("Doublon détecté (clé unique) !");
                } else {
                    throw e;
                }
            }
        }
        impositionsTfuRepository.save(impositionsTfu);
        return n;
    }

    @Override
    public List<DonneesImpositionTfu> getDonneesFiscalesByImposition(Long impositionsId) {
        return donneesImpositionTfuRepository.findAllByImpositionsTfu_Id(impositionsId);
    }

    @Override
    public List<DonneesImpositionTfu> getDonneesFiscalesByImpositionArrondissement(Long impositionsId, Long arrondissementId) {
        Optional<Arrondissement> optionalArrondissement=arrondissementRepository.findById(arrondissementId);
        if(optionalArrondissement.isPresent()){
            return donneesImpositionTfuRepository.findAllByImpositionsTfu_IdAndCodeArrondissement(impositionsId,optionalArrondissement.get().getCode());
        }else {
            return null;
        }
    }
}
