package com.app.ServicesImpl;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

import javax.transaction.Transactional;

import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import com.app.Config.JwtUtils;
import com.app.Dto.AffaireDto;
import com.app.Dto.AffaireSaveMany;
import com.app.Dto.AssureDto;
import com.app.Dto.SouscriptionDto;
import com.app.Entity.Affaire;
import com.app.Entity.Assure;
import com.app.Entity.Conjoint;
import com.app.Entity.Enfant;
import com.app.Entity.User;
import com.app.Repository.AffaireRepository;
import com.app.Repository.AssureRepository;
import com.app.Repository.ConjointRepository;
import com.app.Repository.EnfantRepository;
import com.app.Service.AuthUserService;
import com.app.Services.AffaireService;
import com.app.Services.SouscriptionService;
import com.app.Validations.ObjectsValidator;
import com.app.enums.UserRole;
import com.app.exceptions.AffaireNotFoundExcep;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import lombok.AllArgsConstructor;


@Service
@AllArgsConstructor
@Transactional
public class AffaireImpl implements AffaireService{

	private  PasswordEncoder passwordEncoder;
	private  JwtUtils jwtUtils;

	   private AffaireRepository affaireRepository;
	   private EnfantRepository enfRepository;
	   private AssureRepository assuRepository;
       private ConjointRepository conjRepository;
       private SouscriptionService souscriptionService;
       private EnfantRepository enfantRepository;
	   private final   ObjectsValidator<AffaireDto> objectsValidator;


	    private AuthUserService authUser;
	   @Override
		public AffaireSaveMany saveAffaire(AffaireSaveMany affaireDtoSavemany) {
			return affaireDtoSavemany;
	   }
		@Override
		public void delete(Long id) throws AffaireNotFoundExcep {
			Affaire aff = affaireRepository.findById(id)
					.orElseThrow(()-> new AffaireNotFoundExcep("AffaireNotFound"));

			affaireRepository.deleteById(id);
		}

		@Override
		public AffaireDto findById(Long id) throws AffaireNotFoundExcep {
			Affaire aff = affaireRepository.findById(id)
					.orElseThrow(()-> new AffaireNotFoundExcep("AffaireNotFound"));

			return AffaireDto.fromEntity(aff) ;
		}

		/*@Override
		public AffaireDto findBySouscriptionId(Long id) {
			List<Affaire> aff = affaireRepository.findBySouscriptionId(id) ;
			if (!aff.isEmpty()) {
				return AffaireDto.fromEntity(aff.get(0)) ;
			}
			return null;
		}*/
		@Override
		public AffaireDto findBySouscriptionId(Long id) {
		    Affaire aff = affaireRepository.findBySouscriptionId(id);
		    System.out.println("aaaaaaa");
		    System.out.println(aff);
		    System.out.println("aaaaaaa");
		    if (aff!= null) {
			    System.out.println("bbbbbbb");
			    System.out.println(aff.getIdaff());
		        return AffaireDto.fromEntity(aff);
		    } else {
		        throw new RuntimeException("Affaire not found for souscription ID: " + id);
		    }
		}

		@Override
		public List<AffaireDto> findAllAffaire() {
			return affaireRepository.findAll()
					.stream()
					.map(AffaireDto::fromEntity)
					.collect(Collectors.toList());
		}

		@Override
		public void addAffaireToEnfant(String nameEnfant, String nameaffaire) {

		}
		

	@Override
	public Long save(AffaireDto affaireDto) {
/*
		User user ;
		User savedUser = null ;

		Affaire aff = AffaireDto.toEntity(affaireDto);
		Assure assu =aff.getAssure();
		
		System.out.println("assure " +assu.getEmail());
		System.out.println("conj " +aff.getConjoint());
		//System.out.println("enfants set " +aff.getEnfants());
		SouscriptionDto souscrip = souscriptionService.findById(aff.getSouscription().getId());

		String Data = souscrip.getData();
		System.out.println("Souscription " +Data);
		JsonParser parser = new JsonParser();
		//Creating JSONObject from String using parser
		JsonObject JSONObject = parser.parse(Data).getAsJsonObject();

		Assure assureExist = assuRepository.findByEmail(assu.getEmail());
		System.out.println("assure existe" +assureExist);

		if(assureExist!=null) {
			assu.setDateNaissance(assu.getDateNaissance());
			assu.setRegime(assu.getRegime());
			assu.setCodePostal(assu.getCodePostal());
			String nom = assu.getFirstname();
			String prenom = assu.getLastname();
			assu.setNom(nom);
			assu.setPrenom(prenom);
			assu.setFirstname(assureExist.getFirstname());
			assu.setLastname(assureExist.getLastname());
			assu.setId(assureExist.getId());
			Assure savedAssure = assuRepository.save(assu);
        	aff.setAssure(savedAssure);
		}
		else {
		        	user =new Assure();
					user = AssureDto.toEntity(affaireDto.getAssureDto());
					System.out.println("assureDTO existe" +user);
					user.setRole(UserRole.ASSURE);
					user.setPassword("");
					assu.setDateNaissance(assu.getDateNaissance());
					assu.setRegime(assu.getRegime());
					assu.setCodePostal(assu.getCodePostal());
					String nom = assu.getFirstname();
					String prenom = assu.getLastname();
					assu.setNom(nom);
					assu.setPrenom(prenom);
					Assure savedAssure = assuRepository.save(assu);
		        	aff.setAssure(savedAssure);
		 }



			Conjoint conj =aff.getConjoint();

        	System.out.println("ConjointMoi : ");
        	System.out.println(conj);

			  Conjoint cSaved=conjRepository.save(conj);
			  aff.setConjoint(cSaved);
			       // }

		     //}
		    // else //if(conj==null)
		      System.out.println("Conjoint null !!!!");

			Set<Enfant> enfs=aff.getEnfants();
				    //if(JSONObject.get("enfants").isJsonPrimitive())
		    String enfantsValue = JSONObject.get("enfants").getAsString();
	        if (!enfantsValue.isEmpty()) {

				    	System.out.println("Object not null children: ");
						JsonElement Childrens = JSONObject.get("enfants");

						System.out.println("Object children: "+Childrens);

						String jsonString = Childrens.getAsString();

						String cleanedString = jsonString.replaceAll("\"", "");

						System.out.println("Object children Array of string: "+cleanedString);

						JsonArray jsonArray = JsonParser.parseString(jsonString).getAsJsonArray();
						System.out.println("Object children Array: "+jsonArray);


				     if(jsonArray!=null){
				        Set<Enfant>enfants=new HashSet<>();
				    	//for(Enfant e:gsonList) {
				        for (JsonElement enfant : jsonArray) {
						    JsonObject enfantObj = enfant.getAsJsonObject();
						    System.out.println("Object children json: "+enfantObj);

						    String  date_naissance_children     = enfantObj.get("dateNaissance").getAsString();
						    String  regime_children = enfantObj.get("regime").getAsString();

					        //Enfant enf=enfRepository.getEnfant(e.getFirstname(),e.getLastname(), e.getDateNaissance());
					        //System.out.println(e);

					        Enfant e = new Enfant();
					        e.setDateNaissance(date_naissance_children);
					        e.setRegimeEnf(regime_children);

					        Enfant ef=enfRepository.save(e);
					        enfants.add(ef);
					        aff.setEnfants(enfants);

				    	}
				    	aff.setEnfants(enfants);
				    }
				    }
			        Affaire savedAffaire= affaireRepository.save(aff);
			        System.out.println("Affaire saved avec succes");
			        return AffaireDto.fromEntity(savedAffaire).getId();
			        //return "true";*/
		
		
	    Affaire affby;
	    long id = affaireDto.getId(); 
	    System.out.println("Souscription id" +id);
	    Affaire aff = AffaireDto.toEntity(affaireDto);
	    //if (id > 0){
	    	affby  = affaireRepository.findBySouscriptionId(id);
	    	System.out.println("Affaire by souscription" +affby);
	    	System.out.println("Affaire by souscription datee effet" +aff.getDateEffet());
	    	if (affby != null) {
	            // Mise à jour  affaire si existe
	            System.out.println("Affaire trouvée pour la souscription, mise à jour en cours.");
	            affby = AffaireDto.toEntity(affaireDto, affby);
	        } else {
	            // Création  nouvelle affaire
	            affby = AffaireDto.toEntity(affaireDto);
	        }
	    	
	    	// Mise à jour affaire
	        if (aff.getDateEffet() != null) {
	            affby.setDateEffet(aff.getDateEffet());
	            System.out.println("Date d'effet mise à jour: " + aff.getDateEffet());
	        }
	        
	        if (aff.getNvProjet() != null) {
	            affby.setNvProjet(aff.getNvProjet());
	        }
	        
	        if (aff.getIdaff() != null) {
	            affby.setIdaff(aff.getIdaff());
	        }
	        
	        if (aff.getOrigine() != null) {
	            affby.setOrigine(aff.getOrigine());
	        }
	        
	        if (aff.getStatut() != null) {
	            affby.setStatut(aff.getStatut());
	        }
	        
	        if (aff.getDateSignature() != null) {
	            affby.setDateSignature(aff.getDateSignature());
	        }
	   
	    Assure assu = aff.getAssure();
	    System.out.println("assure " + assu.getEmail());

	    // Souscription
	    SouscriptionDto souscrip = souscriptionService.findById(aff.getSouscription().getId());
	    String data = souscrip.getData();
	    System.out.println("Souscription " + data);

	    JsonParser parser = new JsonParser();
	    JsonObject jsonObject = parser.parse(data).getAsJsonObject();

	    // Assuré
	    Assure assureExist = assuRepository.findByEmail(assu.getEmail());
	    if (assureExist != null) {
	        // Mettre à jour assuré existant
	        assureExist.setDateNaissance(assu.getDateNaissance());
	        assureExist.setRegime(assu.getRegime());
	        assureExist.setCodePostal(assu.getCodePostal());
	        assureExist.setNom(assu.getFirstname());
	        assureExist.setPrenom(assu.getLastname());
	        
	        Assure savedAssure = assuRepository.save(assureExist); 
	        if(affby != null){// Enregistrez l'assuré mis à jour
	        	affby.setAssure(savedAssure);
	        }
	    } else {
	        // Créer un nouvel assuré 
	        User user = AssureDto.toEntity(affaireDto.getAssureDto());
	        user.setRole(UserRole.ASSURE);
	        user.setPassword(""); 

	        
	        assu.setDateNaissance(assu.getDateNaissance());
	        assu.setRegime(assu.getRegime());
	        assu.setCodePostal(assu.getCodePostal());
	        assu.setNom(assu.getFirstname());
	        assu.setPrenom(assu.getLastname());

	        // nouvel assuré
	        Assure savedAssure = assuRepository.save(assu);
	        if(affby != null){
	        	affby.setAssure(savedAssure);
	        }
	    }

	    // Conjoint
	    Conjoint conj = aff.getConjoint();
	    System.out.println("Conjoint " + conj);
	    System.out.println("Conjoint Date naissance " + conj.getDateNaissance());

	    
	    
	   if(affby.getConjoint().getId() > 0){
	    	
	    	    
	 	       System.out.println("Conjoint ID " + affby.getConjoint().getId());
	 		   Conjoint conjExist = conjRepository.findById(affby.getConjoint().getId()).orElseThrow();
	 		   System.out.println("Conjoint Existant ID " + conjExist.getId());
	 		   
	 		   conjExist.setCivilite(conj.getCivilite());
	 		   conjExist.setDateNaissance(conj.getDateNaissance());
	 		   conjExist.setEmail(conj.getEmail());
	 		   conjExist.setEtatCivil(conj.getEtatCivil());
	 		   conjExist.setFirstname(conj.getFirstname());
	 		   conjExist.setLastname(conj.getLastname());
	 		   conjExist.setRegimeConj(conj.getRegimeConj());
	 		   affby.setConjoint(conjRepository.save(conjExist));
	 	   
	    }  else {
	    	
	    	System.out.println("Affaire null");
	    	affby.setConjoint(conjRepository.save(conj));
	  
	    }

	   
	 //Enfants
	    //if(affby != null) {
	    Set<Enfant> existingChildren = affby.getEnfants();
	    System.out.println("Enfants" + existingChildren);
	    if (existingChildren == null) {
	        existingChildren = new HashSet<>(); 
	    }
	    
	    Set<Enfant> enfants = new HashSet<>();
	    String enfantsValue = jsonObject.get("enfants").getAsString();
	    if (!enfantsValue.isEmpty()) {
	        JsonArray jsonArray = JsonParser.parseString(enfantsValue).getAsJsonArray();

	        for (JsonElement enfant : jsonArray) {
	            JsonObject enfantObj = enfant.getAsJsonObject();
	            String dateNaissance = enfantObj.get("dateNaissance").getAsString();
	            System.out.println("EnfantsNaissance saisie " + dateNaissance);
	            String regimeEnf = enfantObj.get("regime").getAsString();

	            // Vérifier si l'enfant existe 
	            Optional<Enfant> existingChildOpt = existingChildren.stream()
	                    .filter(
	                    		existingChild -> existingChild.getDateNaissance().equals(dateNaissance)
	                    		)
	                    .findFirst();

	            System.out.println(existingChildOpt);
	            if (existingChildOpt.isPresent()) {
	            	System.out.print("enfants existe");
	                // Si l'enfant existe, mettre à jour 
	                Enfant existingChild = existingChildOpt.get();
	                existingChild.setRegimeEnf(regimeEnf);
	                enfants.add(existingChild); 
	            } else {
	            	System.out.print("enfants creer");
	                // créer  enfant
	                Enfant newChild = new Enfant();
	                newChild.setDateNaissance(dateNaissance);
	                newChild.setRegimeEnf(regimeEnf);
	                enfants.add(enfRepository.save(newChild)); 
	            }
	        }


	        // Supprimer les enfants  plus dans le JSON
	        for (Enfant existingChild : existingChildren) {
	            if (enfants.stream().noneMatch(child -> child.getDateNaissance().equals(existingChild.getDateNaissance()))) {
	               
	            	
	            	affby.getEnfants().remove(existingChild);
	                enfantRepository.delete(existingChild);
	                System.out.println("enfants supprime " + existingChild.getId());
	               
	            }
	        }
	    }
	    
	    ////if(affby != null){
	    	affby.setEnfants(enfants);
	    //}
	   // }
	   
	    Affaire savedAffaire = affaireRepository.save(affby);
	    System.out.println("Affaire saved avec succès");
	    System.out.println(savedAffaire.getId());
	    
	    return savedAffaire.getId();

	}


	@Override
	public List<AffaireDto> listeraffaireByAssure(Long id) {
		List <Affaire>affaire=affaireRepository.getAffairesByAssure(id);
		List<AffaireDto> affaireByAssure=affaire.stream().map(aff->AffaireDto.fromEntity(aff)).collect 		(Collectors.toList());

		return affaireByAssure;
	}


	public Long updateDateEffet(Long affaireId, String newDateEffet) {
	   
		
		Affaire affby = affaireRepository.findBySouscriptionId(affaireId);
	    
	    if (newDateEffet != null) {
	        affby.setDateEffet(newDateEffet);
	        System.out.println("Date d'effet mise à jour: " + newDateEffet);
	    }

	    Affaire savedAffaire = affaireRepository.save(affby);
	    System.out.println("Date d'effet modifiée avec succès");
	    return savedAffaire.getId();
	}

	/*@Override
	public List<EmployeeDTO> listeremplbydept(String namedpt) {
		List<Employee> empls=employeeRepository.getEmployeeByIdNamedpt(namedpt);


		List<EmployeeDTO> empdto=empls.stream().map(emp->EmployeeDTO.fromEntity(emp)).collect(Collectors.toList());
		return empdto;
	}
	 *
	 */



}