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

import io.gmss.fiscad.entities.infocad.metier.ActeurConcerne;
import io.gmss.fiscad.entities.infocad.metier.Enquete;
import io.gmss.fiscad.entities.infocad.metier.EnqueteFiltreResponse;
import io.gmss.fiscad.entities.infocad.metier.Parcelle;
import io.gmss.fiscad.entities.infocad.parametre.Bloc;
import io.gmss.fiscad.entities.rfu.metier.CaracteristiqueParcelle;
import io.gmss.fiscad.entities.rfu.metier.EnqueteBatiment;
import io.gmss.fiscad.entities.rfu.metier.EnqueteUniteLogement;
import io.gmss.fiscad.entities.user.User;
import io.gmss.fiscad.enums.StatusEnquete;
import io.gmss.fiscad.exceptions.BadRequestException;
import io.gmss.fiscad.exceptions.NotFoundException;
import io.gmss.fiscad.interfaces.infocad.metier.EnqueteService;
import io.gmss.fiscad.interfaces.user.UserService;
import io.gmss.fiscad.paylaods.request.EnquetePayLoad;
import io.gmss.fiscad.paylaods.request.EnqueteTraitementPayLoad;
import io.gmss.fiscad.paylaods.request.FiltreEnquetePayLoad;
import io.gmss.fiscad.paylaods.response.*;
import io.gmss.fiscad.paylaods.response.FicheResponse.*;
import io.gmss.fiscad.repositories.decoupage.ArrondissementRepository;
import io.gmss.fiscad.repositories.decoupage.CommuneRepository;
import io.gmss.fiscad.repositories.decoupage.SecteurRepository;
import io.gmss.fiscad.repositories.infocad.metier.ActeurConcerneRepository;
import io.gmss.fiscad.repositories.infocad.metier.EnqueteRepository;
import io.gmss.fiscad.repositories.infocad.metier.ParcelleRepository;
import io.gmss.fiscad.repositories.infocad.parametre.BlocRepository;
import io.gmss.fiscad.repositories.infocad.parametre.StructureRepository;
import io.gmss.fiscad.repositories.rfu.metier.CaracteristiqueParcelleRepository;
import io.gmss.fiscad.repositories.rfu.metier.EnqueteBatimentRepository;
import io.gmss.fiscad.repositories.rfu.metier.EnqueteUniteLogementRepository;
import io.gmss.fiscad.repositories.user.UserRepository;
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
import jakarta.persistence.Query;
import lombok.RequiredArgsConstructor;
import org.modelmapper.ModelMapper;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

@Service
@RequiredArgsConstructor
public class EnqueteServiceImpl implements EnqueteService {
    private Authentication authentication;
    private final EnqueteRepository enqueteRepository;
    private final BlocRepository blocRepository;
    private final ParcelleRepository parcelleRepository;
    private final UserRepository userRepository;
    private final UserService userService;
    private final CommuneRepository communeRepository;
    private final ArrondissementRepository arrondissementRepository;
    private final ActeurConcerneRepository acteurConcerneRepository;
    private final ModelMapper modelMapper;
    private final CaracteristiqueParcelleRepository caracteristiqueParcelleRepository;
    private final EnqueteBatimentRepository enqueteBatimentRepository;
    private final EnqueteUniteLogementRepository enqueteUniteLogementRepository;
    private final SecteurRepository secteurRepository;
    private final StructureRepository structureRepository;

    @PersistenceContext
    private final EntityManager em;


    @Override
    public Enquete createEnquete(EnquetePayLoad enquetePayLoad) throws BadRequestException {
        Optional<User> optionalUser = userRepository.findById(enquetePayLoad.getUserId());
        if (!optionalUser.isPresent()) {
            throw new BadRequestException("Impossible d'enregistrer une enquête avec un enquêteur inexistant");
        }
        Optional<Bloc> optionalBloc = blocRepository.findById(enquetePayLoad.getBlocId());
        if (!optionalBloc.isPresent()) {
            throw new BadRequestException("Impossible d'enregistrer une enquête avec un bloc inexistant");
        }
        Optional<Parcelle> optionalParcelle = parcelleRepository.findById(enquetePayLoad.getParcelleId());
        if (!optionalParcelle.isPresent()) {
            throw new BadRequestException("Impossible d'enregistrer une enquête avec une parcelle inexistante");
        }
        Enquete enquete = new Enquete();
        enquete.setDateEnquete(LocalDate.now());
        enquete.setBloc(optionalBloc.get());
        enquete.setUser(optionalUser.get());
        enquete.setParcelle(optionalParcelle.get());
        enquete.setLitige(enquetePayLoad.isLitige());
        enquete.setStatusEnquete(StatusEnquete.EN_COURS);
        enquete.setObservationParticuliere(enquetePayLoad.getObservationParticuliere());
        return enqueteRepository.save(enquete);
    }

    @Override
    public List<EnqueteResponse> getEnqueteCommuneArrondBloc() {
        return enqueteRepository.getEnqueteComArrondBloc();
    }

    @Override
    public List<EnqueteFiltreResponse> getEnqueteCommuneArrondBlocFiltre(FiltreEnquetePayLoad filtreEnquetePayLoad) {
        String condition = "";
        Query query;
        String sql = "select distinct " +
                " e.id," +
                " e.parcelle_id as parcelleId," +
                " c.id as communeId, " +
                " c.nom as communeNom, " +
                " a.id as arrondissementId, " +
                " a.nom as arrondissementNom, " +
                " b.id as blocId," +
                " b.nom as blocNom, " +
                " s.id as structureId, " +
                " s.nom as structureNom, " +
                " e.litige," +
                " e.status_enquete as statusEnquete, " +
                " e.date_finalisation as dateFinalisation, " +
                " e.date_validation as dateValidation, " +
                " e.date_synchronisation as dateSynchronisation, " +
                " e.synchronise, " +
                " coalesce(per.nom_ou_sigle,'') as nomSigle, " +
                " coalesce(per.prenom_ou_raison_sociale,'') as prenomRaisonSociale," +
                " tp.libelle as typePersonne," +
                " td.libelle as typeDomaine, " +
                " nd.libelle as natureDomaine, " +
                " p.nup_provisoire as nupProvisoire, " +
                " p.qip as qip, " +
                " p.num_titre_foncier as numTitreFoncier " +
                " from enquete e " +
                " inner join bloc b on b.id=e.bloc_id " +
                " inner join arrondissement a on a.id= b.arrondissement_id  " +
                " inner join commune c on c.id=a.commune_id " +
                " inner join structure s on s.id=b.structure_id " +
                " inner join parcelle p on p.id=e.parcelle_id " +
                " inner join nature_domaine nd on nd.id=p.nature_domaine_id " +
                " inner join type_domaine td on td.id=nd.type_domaine_id " +
                " inner join acteur_concerne ac on ac.enquete_id=e.id " +
                " inner join personne per on per.id=ac.personne_id " +
                " left join type_personne tp on tp.id=per.type_personne_id " +
                " where ac.role_acteur='PROPRIETAIRE' ";

        if (filtreEnquetePayLoad.getCommuneId() != null) {
            condition += " AND c.id = " + filtreEnquetePayLoad.getCommuneId();
        }
        if (filtreEnquetePayLoad.getArrondissementId() != null) {
            condition += " AND a.id = " + filtreEnquetePayLoad.getArrondissementId();
        }
        if (filtreEnquetePayLoad.getStructureId() != null) {
            condition += " AND s.id = " + filtreEnquetePayLoad.getStructureId();
        }
        if (filtreEnquetePayLoad.getParcelleId() != null) {
            condition += " AND p.id = " + filtreEnquetePayLoad.getParcelleId();
        }
        if (filtreEnquetePayLoad.getBlocId() != null) {
            condition += " AND b.id = " + filtreEnquetePayLoad.getBlocId();
        }
        if (filtreEnquetePayLoad.getNomPersonne() != null) {
            condition += " AND per.nom_ou_sigle like '%" + filtreEnquetePayLoad.getNomPersonne() + "%'";
        }
        if (filtreEnquetePayLoad.getPrenomPersonne() != null) {
            condition += " AND per.prenom_ou_raison_sociale like '%" + filtreEnquetePayLoad.getPrenomPersonne() + "%'";
        }
        if (filtreEnquetePayLoad.getNatureDomaneId() != null) {
            condition += " AND nd.id = " + filtreEnquetePayLoad.getNatureDomaneId();
        }
        if (filtreEnquetePayLoad.getTypeDomaineId() != null) {
            condition += " AND td.id = " + filtreEnquetePayLoad.getTypeDomaineId();
        }
        if (filtreEnquetePayLoad.getTypePersonneId() != null) {
            condition += " AND tp.id = " + filtreEnquetePayLoad.getTypePersonneId();
        }
        /////////////////
        if (filtreEnquetePayLoad.getEnqueteurId() != null) {
            condition += " AND e.user_id = " + filtreEnquetePayLoad.getEnqueteurId();
        }

        if (filtreEnquetePayLoad.getStatutEnquete() != null) {
            condition += " AND e.status_enquete = " + filtreEnquetePayLoad.getStatutEnquete();
        }

        if (filtreEnquetePayLoad.getLitige() != null) {
            condition += " AND e.litige is " + filtreEnquetePayLoad.getLitige();
        }

        if (filtreEnquetePayLoad.getSecteurId() != null) {
            condition += " AND b.secteur_id = " + filtreEnquetePayLoad.getSecteurId();
        }

        StringBuilder sb = new StringBuilder(sql).append(condition);
        query = em.createNativeQuery(sb.toString(), EnqueteFiltreResponse.class);
        List<EnqueteFiltreResponse> enqueteFiltreResponses = query.getResultList();

        return enqueteFiltreResponses;
    }

    @Override
    public Enquete updateEnquete(EnquetePayLoad enquetePayLoad) throws NotFoundException {
        if (enquetePayLoad.getIdBackend() == null) {
            throw new BadRequestException("Impossible de mettre à jour une enquête ayant un id null.");
        }
        if (!enqueteRepository.existsById(enquetePayLoad.getIdBackend())) {
            throw new NotFoundException("Impossible de trouver l'enquête que vous désirez modifier.");
        }
        Optional<User> optionalUser = userRepository.findById(enquetePayLoad.getUserId());
        if (!optionalUser.isPresent()) {
            throw new BadRequestException("Impossible d'enregistrer une enquête avec un enquêteur inexistant");
        }
        Optional<Bloc> optionalBloc = blocRepository.findById(enquetePayLoad.getBlocId());
        if (!optionalBloc.isPresent()) {
            throw new BadRequestException("Impossible d'enregistrer une enquête avec un bloc inexistant");
        }
        Optional<Parcelle> optionalParcelle = parcelleRepository.findById(enquetePayLoad.getParcelleId());
        if (!optionalParcelle.isPresent()) {
            throw new BadRequestException("Impossible d'enregistrer une enquête avec une parcelle inexistante");
        }
        Enquete enquete = enqueteRepository.findById(enquetePayLoad.getParcelleId()).get();
        enquete.setBloc(optionalBloc.get());
        enquete.setUser(optionalUser.get());
        enquete.setParcelle(optionalParcelle.get());
        enquete.setLitige(enquetePayLoad.isLitige());
        enquete.setDateFinalisation(enquetePayLoad.getDateFinalisation());
        enquete.setStatusEnquete(enquetePayLoad.getStatusEnquete());
        enquete.setObservationParticuliere(enquetePayLoad.getObservationParticuliere());
        return enqueteRepository.save(enquete);
    }

    @Override
    public void deleteEnquete(Long id) throws NotFoundException {
        Optional<Enquete> optionalEnquete = enqueteRepository.findById(id);
        if (optionalEnquete.isPresent()) {
            enqueteRepository.deleteById(optionalEnquete.get().getId());
        } else {
            throw new NotFoundException("Impossible de trouver l'enquête que vous désirez supprimer.");
        }
    }

    @Override
    public Page<Enquete> getEnqueteList(Pageable pageable) {
        return enqueteRepository.findAll(pageable);
    }

    @Override
    public List<Enquete> getEnqueteList() {
        return enqueteRepository.findAll();
    }

    @Override
    public Optional<Enquete> getEnqueteById(Long id) {
        if (enqueteRepository.existsById(id)) {
            return enqueteRepository.findById(id);
        } else {
            throw new NotFoundException("Impossible de trouver l'enquête.");
        }
    }

    @Override
    public Enquete validerEnquete(EnqueteTraitementPayLoad enqueteTraitementPayLoad) {
        if (enqueteTraitementPayLoad == null) {
            throw new BadRequestException("Impossible de valider une enquête ayant un id null.");
        }
        Optional<Enquete> optionalEnquete = enqueteRepository.findById(enqueteTraitementPayLoad.getIdBackend());
        if (!optionalEnquete.isPresent()) {
            throw new NotFoundException("Impossible de trouver l'enquête que vous désirez valider.");
        }
        Enquete enquete = optionalEnquete.get();
        enquete.setDateValidation(LocalDate.now());
        enquete.setStatusEnquete(StatusEnquete.VALIDE);
        enquete.setSynchronise(false);
        return enqueteRepository.save(enquete);
    }

    @Override
    public Enquete rejeterEnquete(EnqueteTraitementPayLoad enqueteTraitementPayLoad) {
        if (enqueteTraitementPayLoad.getIdBackend() == null) {
            throw new BadRequestException("Impossible de rejeter une enquête ayant un id null.");
        }
        Optional<Enquete> optionalEnquete = enqueteRepository.findById(enqueteTraitementPayLoad.getIdBackend());
        if (!optionalEnquete.isPresent()) {
            throw new NotFoundException("Impossible de trouver l'enquête que vous désirez rejeter.");
        }
        Enquete enquete = optionalEnquete.get();
        enquete.setDateRejet(LocalDate.now());
        enquete.setDescriptionMotifRejet(enqueteTraitementPayLoad.getMotifRejet());
        enquete.setStatusEnquete(StatusEnquete.REJETE);
        enquete.setSynchronise(false);
        return enqueteRepository.save(enquete);
    }

    @Override
    public List<Enquete> validerEnquete(List<EnqueteTraitementPayLoad> enqueteTraitementPayLoads) {
        List<Enquete> enquetes = new ArrayList<>();
        try {
            for (EnqueteTraitementPayLoad enqueteTraitementPayLoad : enqueteTraitementPayLoads) {
                enquetes.add(validerEnquete(enqueteTraitementPayLoad));
            }
        } catch (Exception e) {
            enquetes.add(null);
        }
        return enquetes;
    }

    @Override
    public List<Enquete> rejeterEnquete(List<EnqueteTraitementPayLoad> enqueteTraitementPayLoads) {
        List<Enquete> enquetes = new ArrayList<>();
        try {
            for (EnqueteTraitementPayLoad enqueteTraitementPayLoad : enqueteTraitementPayLoads) {
                enquetes.add(rejeterEnquete(enqueteTraitementPayLoad));
            }
        } catch (Exception e) {
            enquetes.add(null);
        }
        return enquetes;
    }

    @Override
    public Enquete finaliserEnquete(Long enqueteId) {
        if (enqueteId == null) {
            throw new BadRequestException("Impossible de finaliser une enquête ayant un id null.");
        }
        Optional<Enquete> optionalEnquete = enqueteRepository.findById(enqueteId);
        if (!optionalEnquete.isPresent()) {
            throw new NotFoundException("Impossible de trouver l'enquête que vous désirez finaliser.");
        }
        optionalEnquete.get().setDateFinalisation(LocalDate.now());
        optionalEnquete.get().setStatusEnquete(StatusEnquete.FINALISE);
        return enqueteRepository.save(optionalEnquete.get());
    }

    @Override
    public Enquete reglerLitigeEnquete(Long enqueteId) {
        if (enqueteId == null) {
            throw new BadRequestException("Impossible de régler le litige d'une enquête ayant un id null.");
        }
        Optional<Enquete> optionalEnquete = enqueteRepository.findById(enqueteId);
        if (!optionalEnquete.isPresent()) {
            throw new NotFoundException("Impossible de trouver l'enquête dont vous désirez régler le litige.");
        }
        optionalEnquete.get().setDateLitigeResolu(LocalDate.now());
        optionalEnquete.get().setLitige(false);
        optionalEnquete.get().setStatusEnquete(StatusEnquete.EN_COURS);
        return enqueteRepository.save(optionalEnquete.get());
    }


    @Override
    public UserDecoupageEnqResponses getDecoupageAdminUserConnecterAndStat() {
        String userName = "";
        try {
            authentication = SecurityContextHolder.getContext().getAuthentication();
            userName = authentication.getName();
        } catch (Exception e) {
            return null;
        }

        User user = userService.getUserByUsername(userName);
        //User user = userService.getUserByUsername("admin@gmail.com");
        //User user = userService.getUserByUsername("rnovatopo@gmail.com");


        System.out.println(user.isAdmin());

        List<CommuneEnqResponse> communeEnqResponses =
                user.isAdmin() ? communeRepository.getAdminCommuneEnqResponse() : communeRepository.getCommuneEnqResponse(user.getStructure().getId());


        List<ArrondissementEnqResponse> arrondissementEnqResponses =
                user.isAdmin() ? arrondissementRepository.getAdminArrondissementEnqResponse() : arrondissementRepository.getArrondissementEnqResponse(user.getStructure().getId());

        List<BlocEnqResponse> blocEnqResponses =
                user.isAdmin() ? blocRepository.getAdminBlocEnqResponse() : blocRepository.getBlocEnqResponse(user.getStructure().getId());

        UserDecoupageEnqResponses userDecoupageEnqResponses = new UserDecoupageEnqResponses();
        userDecoupageEnqResponses.setCommunes(communeEnqResponses);
        userDecoupageEnqResponses.setArrondissements(arrondissementEnqResponses);
        userDecoupageEnqResponses.setBlocs(blocEnqResponses);
        return userDecoupageEnqResponses;
    }


    @Override
    public UserDecoupageEnqResponses getDecoupageAdminUserConnecterAndStatForDgi() {
        String userName = "";
        try {
            authentication = SecurityContextHolder.getContext().getAuthentication();
            userName = authentication.getName();
        } catch (Exception e) {
            return null;
        }

        User user = userService.getUserByUsername(userName);
        //User user = userService.getUserByUsername("admin@gmail.com");
        //User user = userService.getUserByUsername("rnovatopo@gmail.com");
        System.out.println(user);

        System.out.println(user.isAdmin());

        List<CommuneEnqResponse> communeEnqResponses =
                user.isAdmin() ? communeRepository.getAdminCommuneEnqResponse() : communeRepository.getCommuneEnqResponse(user.getStructure().getId());


        List<StructureEnqResponse> structureEnqResponses =
                user.isAdmin() ? structureRepository.getAdminStructureEnqResponse() : structureRepository.getStructureEnqResponse(user.getStructure().getId());



        List<SecteurEnqResponse> secteurEnqResponses =
                user.isAdmin() ? secteurRepository.getAdminSecteurEnqResponse() : secteurRepository.getSecteurEnqResponse(user.getStructure()==null?0l:user.getStructure().getId(),user.getIdSecteurCourant()==null?0l:user.getIdSecteurCourant());


        UserDecoupageEnqResponses userDecoupageEnqResponses = new UserDecoupageEnqResponses();
        userDecoupageEnqResponses.setCommunes(communeEnqResponses);
        userDecoupageEnqResponses.setStructureEnqResponses(structureEnqResponses);
        userDecoupageEnqResponses.setSecteurEnqResponses(secteurEnqResponses);
        return userDecoupageEnqResponses;
    }

    @Override
    public FicheEnqueteResponse getFicheEnquete(Long enqueteId,String nupProvisoir) {

        if(enqueteId==null){
            Optional<Enquete> optionalEnquete = enqueteRepository.findFirstByParcelle_NupProvisoireOrderByDateEnqueteDesc(nupProvisoir);
            if(optionalEnquete.isPresent()){
                enqueteId=optionalEnquete.get().getId();
            }
        }


        Optional<Enquete> optionalEnquete = enqueteRepository.findById(enqueteId);

        List<ActeurConcerne> acteurConcernes = acteurConcerneRepository.findActeurConcerneByEnquete_Id(enqueteId);

        FicheEnqueteResponse ficheEnqueteResponse = new FicheEnqueteResponse(); // payload de réponse global

        FicheEnquetesResponse ficheEnquetesResponse = new FicheEnquetesResponse(); // classe payload de Enquete

        if (optionalEnquete.isPresent()) {
            ficheEnquetesResponse = modelMapper.map(optionalEnquete.get(), FicheEnquetesResponse.class);
        }

        List<CaracteristiqueParcelle> caracteristiqueParcelles = caracteristiqueParcelleRepository.findAllByEnquete_Id(enqueteId);

        List<EnqueteBatiment> enqueteBatiments = enqueteBatimentRepository.findAllByEnquete_Id(enqueteId);

        List<EnqueteUniteLogement> enqueteUniteLogements = enqueteUniteLogementRepository.findAllByEnquete_Id(enqueteId);

        ficheEnquetesResponse.setCaracteristiquesParcelles(caracteristiqueParcelles);
        ficheEnquetesResponse.setEnquetesBatiments(enqueteBatiments);
        ficheEnquetesResponse.setEnquetesUniteLogements(enqueteUniteLogements);
        ficheEnqueteResponse.setEnquete(ficheEnquetesResponse);
        ficheEnqueteResponse.setActeurConcernes(acteurConcernes);

        return ficheEnqueteResponse;
    }

    @Override
    public List<EnqueteNonSyncResponse> getEnqueteValideNonSynch(Long terminalId) {
        return enqueteRepository.getEnqueteValNonSync(terminalId);
    }


}
