package com.hpay.hpay_mobile_api.services;

import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.PutObjectRequest;
import com.google.zxing.WriterException;
import com.hpay.hpay_mobile_api.DTO.ErrorResponse;
import com.hpay.hpay_mobile_api.DTO.LoginRequest;
import com.hpay.hpay_mobile_api.DTO.SuccessResponse;
import com.hpay.hpay_mobile_api.entities.*;
import com.hpay.hpay_mobile_api.repositories.*;
import com.hpay.hpay_mobile_api.security.JwtTokenUtil;
import com.hpay.hpay_mobile_api.utils.PasswordUtils;
import com.hpay.hpay_mobile_api.utils.SMSapi;
import com.hpay.hpay_mobile_api.utils.SendEmail;
import jakarta.mail.MessagingException;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.math.BigDecimal;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import com.hpay.hpay_mobile_api.entities.ParrainCode;
import java.awt.image.BufferedImage;

import javax.imageio.ImageIO;
import java.nio.file.Paths;


@Service
public class AuthService {

    @Autowired
    private LoginClientRepository loginClientRepository;

    @Autowired
    private ClientRepository clientRepository;

    @Autowired
    private PayRepository payRepository;

    @Autowired
    private TypeCompteRepository  typeCompteRepository ;

    @Autowired
    private CompteRepository compteRepository;

    @Autowired
    private ParrainageRepository parrainageRepository;

    @Autowired
    private ParrainCodeRepository  parrainageCodeRepository;

    @Autowired
    private S3Service s3Service;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Autowired
    private PhotoService photoService;

    private final BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

    @Value("${client.photo.upload-dir}")
    private String uploadDir; // The directory to store photos

    @Value("${client.photo.profile.upload-dir}")
    private String clientPhotoUploadDir; // The directory to store photos

    @Value("${client.photo.profile.base-url}")
    private String clientPhotoBaseUrl; // The directory to store photos


    @Value("${client.photo.base-url}")
    private String photoBaseUrl; // The directory to store photos

    @Value("${client.sponsorship.registration-base-url}")
    private String registrationBaseUrl;


    @Autowired
    private VilleRepository villeRepository;

    @Autowired
    private ClientService clientService;

    @Autowired
    private CompteService compteService;


    @Value("${aws.s3.bucketName}")
    private String bucketName;

    private final AmazonS3 amazonS3;

    public AuthService (AmazonS3 amazonS3) {
        this.amazonS3 = amazonS3;
    }



    // Signup functionality - User registration
    @Transactional
    public Object signup(LoginRequest loginRequest) throws IOException, WriterException {

        //fetch the Pays object
        Pays pays = payRepository.findById(loginRequest.getIdPays()).orElse(null);
        if (pays == null) {
            return new ErrorResponse("Pays not found", 409);
        }

        //fetch the Ville object
        Ville ville = villeRepository.findById(loginRequest.getIdVille()).orElse(null);
        if (ville == null) {
            return new ErrorResponse("Pays not found", 409);
        }

        // fetch the login Client Object
        LoginClient existingClient = loginClientRepository.findByLogin(loginRequest.getLogin());
        if (existingClient != null /*&&   existingClient.getClient().getPays().getId().equals(loginRequest.getIdPays())*/) {
            return new ErrorResponse("Client already exists", 409);
        }


        // creation of the client objet
        Date currentDate = new Date();  // This returns the current date and time

        // Required fields for instantiation
        String clientCode = "CL12345";
        String numPiece = "123456789";
        Integer idTypePiece = 1;
        Integer idAgence = 2;
        String valider = "0";  // Assuming '0' is for 'incomplet' status
        Float gainCommercial= 0.0f;
        String gainPaye="0";
        Integer idCommercial = 0;
        Integer idGestionnaire=0;




        // Create the Client object using the constructor with required fields
        Client client = new Client(
                clientCode,
                numPiece,
                currentDate,
                ville,
                idTypePiece,
                pays,
                idAgence,
                valider,
                gainCommercial,
                gainPaye,
                idCommercial,
                idGestionnaire,
                loginRequest.getLogin()
        );

        // save client
        client = clientRepository.save(client);

        ParrainCode parrainCode = new ParrainCode();
        String code = "HPAY_" + client.getId() + UUID.randomUUID().toString().substring(0, 8).toUpperCase();

        while (parrainageCodeRepository.findByCodeParrainage(code)!= null){
            code = "HPAY_" + client.getId() + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
        }

        parrainCode.setCodeParrainage(code);
        parrainCode.setUpdate(false);
        LocalDateTime currentDateTime = LocalDateTime.now();
        parrainCode.setDateCreation(currentDateTime);
        parrainCode.setClient(client);



        //String QRCodeFileName=  UUID.randomUUID().toString() + "-" + client.getId()+".png";
        // String url = s3Service.generateQRCodeAndUploadToS3(QRCodeText,QRCodeFileName);

        String QRCodeText = registrationBaseUrl + code;
        BufferedImage qrImage = photoService.generateQRCodeImage(QRCodeText);
        String url = photoService.uploadQrCode(qrImage,code);


        parrainCode.setQrcode(url);
        parrainCode = parrainageCodeRepository.save(parrainCode);


        client.setParrainCode(parrainCode);
        client.setValider("2");
        client = clientRepository.save(client);


        // generate salt of 64 bits
        String salt = PasswordUtils.generateSalt(64);
       // String salt = UUID.randomUUID().toString();

        // Encrypt the password
        String encryptedPassword = PasswordUtils.hashPassword(loginRequest.getPassword(), salt);
       // String encryptedPassword = passwordEncoder.encode(loginRequest.getPassword());

        // Create a LoginClient object
        LoginClient loginClient = new LoginClient();
        loginClient.setLogin(loginRequest.getLogin());
        loginClient.setPassword(encryptedPassword);
        loginClient.setSalt(salt);
        loginClient.setUsername(loginRequest.getLogin());  // You can adjust this to have different logic for username
        loginClient.setActif("0");  // Default status
        Random rand = new Random();
        int randomNum = 1000 + rand.nextInt(9000);
        String activationCode = String.valueOf(randomNum);
        loginClient.setActivationCode(activationCode);  // Generate an activation code
        loginClient.setClient(client);
        loginClient.setEmailvalidate("0");


        // Save login client
        loginClient= loginClientRepository.save(loginClient);

        // build the response map
        HashMap<String, Object> map = new HashMap<>();
        map.put("data",loginClient);

        // send the activation code by SMS

        SMSapi sms= new SMSapi();
        //
        sms.alaSMS( pays.getIndicatif() + loginRequest.getLogin(), "Hpay: votre code de vérification  est "+activationCode+" Ne le partargez pas. " +
                "Si vous ne l'avez pas demandé veillez ignorer ce message.");

        // return the response
        return new SuccessResponse("User registered successfully", 201,map );

    }


    public static boolean contientTypeCompte (List<Compte> comptes, int idTypeCompteRecherche) {
        for (Compte compte : comptes) {
            if (compte.getTypeCompte().getTypeCompte() != null &&
                    compte.getTypeCompte().getIdTypeCompte() == idTypeCompteRecherche) {
                return true;
            }
        }
        return false;
    }



    // Sign-in functionality - User authentication
    public Object signin(String login, String password) throws IOException, WriterException {

        LoginClient loginClient = loginClientRepository.findByLogin(login);
        Client client = loginClient.getClient();

        if (loginClient == null) {
            return new ErrorResponse("Invalid credentials", 401);  // Invalid login response
        }

        List <Compte> compteClients =  loginClient.getClient().getComptes();
        Date today = new Date();


        if(loginClient.getClient().getParrainCode()== null){

            ParrainCode parrainCode = new ParrainCode();
            String code = "HPAY_" + loginClient.getClient().getId() + UUID.randomUUID().toString().substring(0, 8).toUpperCase();

            while (parrainageCodeRepository.findByCodeParrainage(code)!= null){
                code = "HPAY_" + loginClient.getClient().getId() + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
            }

            parrainCode.setCodeParrainage(code);
            parrainCode.setUpdate(false);
            LocalDateTime currentDateTime = LocalDateTime.now();
            parrainCode.setDateCreation(currentDateTime);
            parrainCode.setClient(loginClient.getClient());


            /*String QRCodeText= "https://devmobile.hpaytest.cash/sign-up.php?ref="+code;
            String QRCodeFileName =  UUID.randomUUID().toString() + "-" + loginClient.getClient().getId()+".png";
            String url = s3Service.generateQRCodeAndUploadToS3(QRCodeText,QRCodeFileName);*/

            String QRCodeText = registrationBaseUrl+code;
            BufferedImage qrImage = photoService.generateQRCodeImage(QRCodeText);
            String url = photoService.uploadQrCode(qrImage,code);
            parrainCode.setQrcode(url);
            parrainCode = parrainageCodeRepository.save(parrainCode);
            client.setParrainCode(parrainCode);

        }




        // compte de device EuR
        if(!contientTypeCompte(compteClients , 4) && !loginClient.getClient().getPays().getDevise().getDevise().equals("EUR")){

            // fetch the account Devise EUR
            TypeCompte EURCompteType = typeCompteRepository.findById(Long.valueOf(4)).orElse(null);
            if (EURCompteType == null) {
                return new ErrorResponse("type compte EUR   not found", 404);
            }

            Compte  EURCompte = new Compte();
            LocalDateTime now4 = LocalDateTime.now();
            DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
            EURCompte.setNumCompte(compteService.generateUniqueNumCompte());
            EURCompte.setSolde(new BigDecimal("0"));
            EURCompte.setRib("#");
            EURCompte.setIban("#");
            EURCompte.setBicSwift("#");
            EURCompte.setCompteSuspendu("0");
            EURCompte.setPays(loginClient.getClient().getPays());
            EURCompte.setDevise("EUR");
            EURCompte.setCloture("0");
            EURCompte.setClient(loginClient.getClient());  // Link the client
            EURCompte.setTypeCompte(EURCompteType);  // Link the type_compte
            EURCompte.setFraisCreationCpt(new BigDecimal("0"));
            EURCompte.setDateCreationCpt(today);
            compteRepository.save(EURCompte);
            compteClients.add(EURCompte);
        }





        // compte de device USD
        if(!contientTypeCompte(compteClients , 1) && !loginClient.getClient().getPays().getDevise().getDevise().equals("USD")){


            // fetch the account Devise USD
            TypeCompte USDCompteType= typeCompteRepository.findById(Long.valueOf(1)).orElse(null);
            if (USDCompteType == null) {
                return new ErrorResponse("type compte USD   not found", 404);
            }

            Compte  USDCompte = new Compte();
            LocalDateTime now2 = LocalDateTime.now();
            DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
            USDCompte.setNumCompte(compteService.generateUniqueNumCompte());
            USDCompte.setSolde(new BigDecimal("0"));
            USDCompte.setRib("#");
            USDCompte.setIban("#");
            USDCompte.setBicSwift("#");
            USDCompte.setCompteSuspendu("0");
            USDCompte.setPays(loginClient.getClient().getPays());
            USDCompte.setDevise("USD");
            USDCompte.setCloture("0");
            USDCompte.setClient(loginClient.getClient());  // Link the client
            USDCompte.setTypeCompte(USDCompteType);  // Link the type_compte
            USDCompte.setFraisCreationCpt(new BigDecimal("0"));
            USDCompte.setDateCreationCpt(today);
            compteRepository.save(USDCompte);
            compteClients.add(USDCompte);

        }

        // compte de device CAD
        if(!contientTypeCompte(compteClients , 3) && !loginClient.getClient().getPays().getDevise().getDevise().equals("CAD")){


            // fetch the account Devise CAD
            TypeCompte CADCompteType= typeCompteRepository.findById(Long.valueOf(3)).orElse(null);
            if (CADCompteType == null) {
                return new ErrorResponse("type compte CAD   not found", 404);
            }

            Compte  CADCompte = new Compte();
            LocalDateTime now3 = LocalDateTime.now();
            DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
            CADCompte.setNumCompte(compteService.generateUniqueNumCompte());
            CADCompte.setSolde(new BigDecimal("0"));
            CADCompte.setRib("#");
            CADCompte.setIban("#");
            CADCompte.setBicSwift("#");
            CADCompte.setCompteSuspendu("0");
            CADCompte.setPays(loginClient.getClient().getPays());
            CADCompte.setDevise("CAD");
            CADCompte.setCloture("0");
            CADCompte.setClient(loginClient.getClient());  // Link the client
            CADCompte.setTypeCompte(CADCompteType);  // Link the type_compte
            CADCompte.setFraisCreationCpt(new BigDecimal("0"));
            CADCompte.setDateCreationCpt(today);
            compteRepository.save(CADCompte);
            compteClients.add(CADCompte);
        }

        // compte de device GBP
        if(!contientTypeCompte(compteClients , 5) && !loginClient.getClient().getPays().getDevise().getDevise().equals("GBP")){


            // fetch the account Devise GBP
            TypeCompte GBPCompteType= typeCompteRepository.findById(Long.valueOf(5)).orElse(null);
            if (GBPCompteType == null) {
                return new ErrorResponse("type compte GBP   not found", 404);
            }

            Compte  GBPCompte = new Compte();
            LocalDateTime now5 = LocalDateTime.now();
            DateTimeFormatter formatter5 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
            GBPCompte.setNumCompte(compteService.generateUniqueNumCompte());
            GBPCompte.setSolde(new BigDecimal("0"));
            GBPCompte.setRib("#");
            GBPCompte.setIban("#");
            GBPCompte.setBicSwift("#");
            GBPCompte.setCompteSuspendu("0");
            GBPCompte.setPays(loginClient.getClient().getPays());
            GBPCompte.setDevise("GBP");
            GBPCompte.setCloture("0");
            GBPCompte.setClient(loginClient.getClient());  // Link the client
            GBPCompte.setTypeCompte(GBPCompteType);  // Link the type_compte
            GBPCompte.setFraisCreationCpt(new BigDecimal("0"));
            GBPCompte.setDateCreationCpt(today);
            compteRepository.save(GBPCompte);
            compteClients.add(GBPCompte);

        }

        // misse à jour des compte d'un client

        client.setComptes(compteClients);
        loginClient.setClient(client);
        loginClientRepository.save(loginClient);


        // Compare password with the encrypted one
        //String hashedInput = PasswordUtils.hashPassword(password+loginClient.getSalt());
        //String salt = loginClient.getSalt();
        //System.out.println("le salt :"+salt);

        Random rand = new Random();
        int randomNum = 1000 + rand.nextInt(9000);
        String activationCode = String.valueOf(randomNum);
        String hashedInput = PasswordUtils.hashPassword(password, loginClient.getSalt());
        // if (passwordEncoder.matches(password, loginClient.getPassword())) {


        if (hashedInput.equals(loginClient.getPassword())) {

            HashMap<String, Object> map = new HashMap<>();
            String data = "data";
            map.put(data,loginClient);
            map.put("token",jwtTokenUtil.generateToken(loginClient.getLogin()));

            if (!loginClient.getActif().equals("1")){
                SMSapi sms= new SMSapi();
                sms.alaSMS( loginClient.getClient().getPays().getIndicatif() + loginClient.getLogin(), "Hpay: votre code de vérification  est "+activationCode+" Ne le partargez pas. " +
                        "Si vous ne l'avez pas demandé veillez ignorer ce message.");
            }

            return new SuccessResponse("Sign-in successful", 200, map);  // Successful login with user details
        } else {
            return new ErrorResponse("Invalid credentials", 401);  // Invalid password response
        }


    }




    // Method to validate the activation code
    @Transactional
    public Object  validateLoginClient(Long idLoginClient, String activationCode) {

        Date today = new Date();

        // fetch login client object
        LoginClient loginClient = loginClientRepository.findById(idLoginClient).orElse(null);

        // return error message if not found
        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        // Check if the activation code matches
        if (loginClient.getActivationCode().equals(activationCode)) {

            // Update the 'actif' field to "1" (active)
            loginClient.setActif("1");

            // fetch the account type 2 (HPay cash)
            TypeCompte hpayCashCompteType= typeCompteRepository.findById(Long.valueOf(2)).orElse(null);
            if (hpayCashCompteType == null) {
                return new ErrorResponse("type compte Hpay cash  not found", 404);
            }

            // fetch the account type 6 (personel)
            TypeCompte personalCompteType= typeCompteRepository.findById(Long.valueOf(6)).orElse(null);
            if (personalCompteType == null) {
                return new ErrorResponse("type compte personnel   not found", 404);
            }

            // fetch the account Devise CAD
            TypeCompte CADCompteType= typeCompteRepository.findById(Long.valueOf(3)).orElse(null);
            if (CADCompteType == null) {
                return new ErrorResponse("type compte CAD   not found", 404);
            }


            // fetch the account Devise EUR
            TypeCompte EURCompteType = typeCompteRepository.findById(Long.valueOf(4)).orElse(null);
            if (EURCompteType == null) {
                return new ErrorResponse("type compte EUR   not found", 404);
            }


            // fetch the account Devise USD
            TypeCompte USDCompteType= typeCompteRepository.findById(Long.valueOf(1)).orElse(null);
            if (USDCompteType == null) {
                return new ErrorResponse("type compte USD   not found", 404);
            }

            // fetch the account Devise GBP
            TypeCompte GBPCompteType= typeCompteRepository.findById(Long.valueOf(5)).orElse(null);
            if (GBPCompteType == null) {
                return new ErrorResponse("type compte GBP   not found", 404);
            }

            // creation of Hpay compte
            Compte  hpayCashCompte = new Compte();
            LocalDateTime now = LocalDateTime.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
            hpayCashCompte.setNumCompte(compteService.generateUniqueNumCompte());
            hpayCashCompte.setSolde(new BigDecimal("0"));
            hpayCashCompte.setRib("#");
            hpayCashCompte.setIban("#");
            hpayCashCompte.setBicSwift("#");
            hpayCashCompte.setCompteSuspendu("0");
            hpayCashCompte.setPays(loginClient.getClient().getPays());
            hpayCashCompte.setDevise("HPC");
            hpayCashCompte.setCloture("0");
            hpayCashCompte.setClient(loginClient.getClient());  // Link the client
            hpayCashCompte.setTypeCompte(hpayCashCompteType);  // Link the type_compte
            hpayCashCompte.setFraisCreationCpt(new BigDecimal("0"));
            hpayCashCompte.setDateCreationCpt(today);
            compteRepository.save(hpayCashCompte);


            // creation of personal account
            Compte  personnalCompte = new Compte();
            LocalDateTime now1 = LocalDateTime.now().plusSeconds(1);
            DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
            personnalCompte.setNumCompte(compteService.generateUniqueNumCompte());
            personnalCompte.setSolde(new BigDecimal("0"));
            personnalCompte.setRib("#");
            personnalCompte.setIban("#");
            personnalCompte.setBicSwift("#");
            personnalCompte.setCompteSuspendu("0");
            personnalCompte.setPays(loginClient.getClient().getPays());
            personnalCompte.setDevise(loginClient.getClient().getPays().getDevise().getDevise());
            personnalCompte.setCloture("0");
            personnalCompte.setClient(loginClient.getClient());  // Link the client
            personnalCompte.setTypeCompte(personalCompteType);  // Link the type_compte
            personnalCompte.setFraisCreationCpt(new BigDecimal("0"));
            personnalCompte.setDateCreationCpt(today);
            compteRepository.save(personnalCompte);

            // adding of personnal and Hpay account in comptes object
            List<Compte> comptes = new ArrayList<>();
            comptes.add(hpayCashCompte);
            comptes.add(personnalCompte);

            // creation des compte de devises

            if(!loginClient.getClient().getPays().getDevise().getDevise().equals("USD")){

                Compte  USDCompte = new Compte();
                LocalDateTime now2 = LocalDateTime.now();
                DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
                USDCompte.setNumCompte(compteService.generateUniqueNumCompte());
                USDCompte.setSolde(new BigDecimal("0"));
                USDCompte.setRib("#");
                USDCompte.setIban("#");
                USDCompte.setBicSwift("#");
                USDCompte.setCompteSuspendu("0");
                USDCompte.setPays(loginClient.getClient().getPays());
                USDCompte.setDevise("USD");
                USDCompte.setCloture("0");
                USDCompte.setClient(loginClient.getClient());  // Link the client
                USDCompte.setTypeCompte(USDCompteType);  // Link the type_compte
                USDCompte.setFraisCreationCpt(new BigDecimal("0"));
                USDCompte.setDateCreationCpt(today);
                compteRepository.save(USDCompte);
                comptes.add(USDCompte);
            }

            if(!loginClient.getClient().getPays().getDevise().getDevise().equals("CAD")){

                Compte  CADCompte = new Compte();
                LocalDateTime now3 = LocalDateTime.now();
                DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
                CADCompte.setNumCompte(compteService.generateUniqueNumCompte());
                CADCompte.setSolde(new BigDecimal("0"));
                CADCompte.setRib("#");
                CADCompte.setIban("#");
                CADCompte.setBicSwift("#");
                CADCompte.setCompteSuspendu("0");
                CADCompte.setPays(loginClient.getClient().getPays());
                CADCompte.setDevise("CAD");
                CADCompte.setCloture("0");
                CADCompte.setClient(loginClient.getClient());  // Link the client
                CADCompte.setTypeCompte(CADCompteType);  // Link the type_compte
                CADCompte.setFraisCreationCpt(new BigDecimal("0"));
                CADCompte.setDateCreationCpt(today);
                compteRepository.save(CADCompte);
                comptes.add(CADCompte);

            }


            if(!loginClient.getClient().getPays().getDevise().getDevise().equals("EUR") ){

                Compte  EURCompte = new Compte();
                LocalDateTime now4 = LocalDateTime.now();
                DateTimeFormatter formatter4 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
                EURCompte.setNumCompte(compteService.generateUniqueNumCompte());
                EURCompte.setSolde(new BigDecimal("0"));
                EURCompte.setRib("#");
                EURCompte.setIban("#");
                EURCompte.setBicSwift("#");
                EURCompte.setCompteSuspendu("0");
                EURCompte.setPays(loginClient.getClient().getPays());
                EURCompte.setDevise("EUR");
                EURCompte.setCloture("0");
                EURCompte.setClient(loginClient.getClient());  // Link the client
                EURCompte.setTypeCompte(EURCompteType);  // Link the type_compte
                EURCompte.setFraisCreationCpt(new BigDecimal("0"));
                EURCompte.setDateCreationCpt(today);
                compteRepository.save(EURCompte);
                comptes.add(EURCompte);

            }

            if(!loginClient.getClient().getPays().getDevise().getDevise().equals("GBP")){

                Compte  GBPCompte = new Compte();
                LocalDateTime now5 = LocalDateTime.now();
                DateTimeFormatter formatter5 = DateTimeFormatter.ofPattern("yyMMddHHmmssSSS");
                GBPCompte.setNumCompte(compteService.generateUniqueNumCompte());
                GBPCompte.setSolde(new BigDecimal("0"));
                GBPCompte.setRib("#");
                GBPCompte.setIban("#");
                GBPCompte.setBicSwift("#");
                GBPCompte.setCompteSuspendu("0");
                GBPCompte.setPays(loginClient.getClient().getPays());
                GBPCompte.setDevise("GBP");
                GBPCompte.setCloture("0");
                GBPCompte.setClient(loginClient.getClient());  // Link the client
                GBPCompte.setTypeCompte(GBPCompteType);  // Link the type_compte
                GBPCompte.setFraisCreationCpt(new BigDecimal("0"));
                GBPCompte.setDateCreationCpt(today);
                compteRepository.save(GBPCompte);
                comptes.add(GBPCompte);
            }


            //get the client Object
            Client client = loginClient.getClient();
            client.setComptes(comptes);
            loginClient.setClient(client);


            // Save the updated LoginClient object
            LoginClient loginClient1 =  loginClientRepository.save(loginClient);
            HashMap<String, Object> map = new HashMap<>();
           // map.put("data",loginClient1);

            return new SuccessResponse("validate successful", 200, map );

        } else {
            // If the activation codes do not match return error response
            return new ErrorResponse("Invalid code", 401);
        }

    }



    @Transactional
    public Object updateActivationCode(Long idLoginClient) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findById(idLoginClient).orElse(null);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        // Update the activation code
        Random rand = new Random();
        int randomNum = 1000 + rand.nextInt(9000);
        String activationCode = String.valueOf(randomNum);
        loginClient.setActivationCode(activationCode);

        SMSapi sms= new SMSapi();
        sms.alaSMS(loginClient.getLogin(), "Hpay: votre code de vérification  est "+activationCode+" Ne le partargez pas. " +
                "Si vous ne l'avez pas demandé veillez ignorer ce message.");


        // Save the updated LoginClient back to the database
        loginClient= loginClientRepository.save(loginClient);
        HashMap<String, Object> map = new HashMap<>();
        map.put("data",loginClient);
        return new SuccessResponse("update succesful", 200, map );
    }


    @Transactional
    public Object updateClientInfo(Long idLoginClient, String nom, String prenoms, String sex, Date dateNaissance, String lieuNaissance) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findById(idLoginClient).orElse(null);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        Client client = loginClient.getClient();
        client.setNom(nom);
        client.setPrenoms(prenoms);
        client.setDateNaissance(dateNaissance);
        client.setLieuNaissane(lieuNaissance);
        client.setSexe(sex);

        loginClient.setClient(client);
        loginClient= loginClientRepository.save(loginClient);
        HashMap<String, Object> map = new HashMap<>();
        map.put("data",loginClient);
        return new SuccessResponse("update succesfull", 200, map );

    }


    // endpoint to add an email to client profil
    @Transactional
    public Object updateEmail(Long idLoginClient, String email) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findById(idLoginClient).orElse(null);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        Client existClient =   clientService.getClientByEmail(email);

        if (existClient != null && !existClient.getId().equals(loginClient.getClient().getId()) ) {
            return new ErrorResponse("email already used", 404);
        }


        Client client = loginClient.getClient();
        client.setEmail(email);
        loginClient.setClient(client);


        Random rand = new Random();
        int randomNum = 1000 + rand.nextInt(9000);
        String activationCode = String.valueOf(randomNum);
        loginClient.setActivationCode(activationCode);

        loginClient= loginClientRepository.save(loginClient);

        try {
            SendEmail.sendEmailValidationCode (email, activationCode, client.getPrenoms());
        }catch (MessagingException e) {
            e.printStackTrace();
        }

        HashMap<String, Object> map = new HashMap<>();
        map.put("data",loginClient);
        return new SuccessResponse("update succesfull", 200, map );
    }


    @Transactional
    public Object uploadClientPhoto(Long idLoginClient, MultipartFile photo) throws IOException, ParseException {

        //System.out.println("hello icic");
        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findById(idLoginClient).orElse(null);

        if (loginClient == null ) {
            return new ErrorResponse("Client not found", 404);
        }

       // String photoUrl =  clientPhotoBaseUrl + photoService.uploadClientPhoto(photo);
        String photoUrl =  photoService.uploadClientPhoto(photo);


        //Upload verso to AWS S3
        /*String photoUrl = "";
        String photoName = UUID.randomUUID().toString() + "-" + photo.getOriginalFilename();
        amazonS3.putObject(new PutObjectRequest(bucketName, photoName , photo.getInputStream(), null));
        photoUrl= amazonS3.getUrl(bucketName, photoName).toString();
        */


        // Update the client's record with the path to the photo
        Client client = loginClient.getClient();
        client.setPhotoClient(photoUrl);
        loginClient.setClient(client);

        loginClient= loginClientRepository.save(loginClient);
        HashMap<String, Object> map = new HashMap<>();
        map.put("data",loginClient);
        return new SuccessResponse("update photo added", 200, map );

    }



    // Method to validate the activation code
    @Transactional
    public Object  validateEmailClient(Long idLoginClient, String activationCode) {

        // fetch login client object
        LoginClient loginClient = loginClientRepository.findById(idLoginClient).orElse(null);

        // return error message if not found
        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        // Check if the activation code matches
        if (loginClient.getActivationCode().equals(activationCode)) {

            // Update the 'actif' field to "1" (active)
            loginClient.setEmailvalidate("1");
            loginClientRepository.save(loginClient);

            try {
                SendEmail.sendAccountCreatedConfirmEmail (
                        loginClient.getClient().getEmail(),
                        loginClient.getClient().getPrenoms(),
                        String.valueOf(loginClient.getLogin())
                );
            }catch (MessagingException e) {
                e.printStackTrace();
            }

            HashMap<String, Object> map = new HashMap<>();
            return new SuccessResponse("validate successful", 200, map );
        } else{
            return new ErrorResponse("not correct code", 404);
        }

    }



    public Object deleteLoginClient(Long id) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findById(id).orElse(null);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        loginClientRepository.deleteById(id);

        HashMap<String, Object> map = new HashMap<>();
        return new SuccessResponse("delete succesfull", 200, map );

    }



    public Object fetchClient(Long id) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findById(id).orElse(null);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }
        else{
            HashMap<String, Object> map = new HashMap<>();
            map.put("data",loginClient);
            return new SuccessResponse("delete succesfull", 200, map );

        }

    }




    //  request password recover
    public Object passwordforgetRequest(String phone) {

        // Find the LoginClient by its id
        LoginClient loginClient = loginClientRepository.findByLogin(phone);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        Random rand = new Random();
        int randomNum = 1000 + rand.nextInt(9000);
        String activationCode = String.valueOf(randomNum);

        loginClient.setActivationCode(activationCode);
        loginClient = loginClientRepository.save(loginClient);

        // send the activation code by SMS
        System.out.println(phone);
        SMSapi sms= new SMSapi();
        sms.alaSMS(phone, "Hpay: Le  code restauration de votre  mot de passe est "+activationCode+". Ne le partargez pas. " +
                "Si vous ne l'avez pas demandé veillez ignorer ce message.");


        HashMap<String, Object> map = new HashMap<>();
        map.put("data",loginClient);
        return new SuccessResponse("update succesfull", 200, map );
    }



    // Method to validate password forgot code
    public Object  validatePasswordForgotCode(String phone, String activationCode) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findByLogin(phone);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        // Check if the activation code matches
        if (loginClient.getActivationCode().equals(activationCode)) {

            HashMap<String, Object> map = new HashMap<>();
            return new SuccessResponse("validate successful", 200, map );

        } else {
            // If the activation codes do not match return error response
            return new ErrorResponse("Invalid code", 401);
        }

    }


    // Method to change the password after request code validation
    public Object  changepassword(String phone, String password) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findByLogin(phone);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        // Generate a salt (UUID can be used here, or any custom salt generation)
        //String salt = UUID.randomUUID().toString();
        String salt = PasswordUtils.generateSalt(64);

        // Encrypt the password
        //String encryptedPassword = passwordEncoder.encode(password);
        String encryptedPassword = PasswordUtils.hashPassword(password, salt);

        loginClient.setSalt(salt);
        loginClient.setPassword(encryptedPassword);

        loginClient = loginClientRepository.save(loginClient);

        // build the response map
        HashMap<String, Object> map = new HashMap<>();
        map.put("data",loginClient);

        // return the response
        return new SuccessResponse("password update succeffully", 201,map );

    }




    // Method to change the password after request code validation
    public Object  changePasswordWithOldPassword(Long id, String oldPassword, String newPassword) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findById(id).orElse(null);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        // verification of the oldPassword: Compare password with the encrypted one
        if (passwordEncoder.matches(oldPassword, loginClient.getPassword())) {

            // Generate a salt (UUID can be used here, or any custom salt generation)
            String salt = UUID.randomUUID().toString();

            // Encrypt the password
            String encryptedPassword = passwordEncoder.encode(newPassword);

            loginClient.setPassword(encryptedPassword);

            loginClient = loginClientRepository.save(loginClient);

            // build the response map
            HashMap<String, Object> map = new HashMap<>();
            map.put("data",loginClient);

            return new SuccessResponse("password successfully update", 200, map);  // Successful login with user details
        } else {
            return new ErrorResponse("Invalid credentials", 401);  // Invalid password response
        }

    }



    public Object fetchClientByPhone(String phone) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findByLogin(phone);

        if ( loginClient == null ) {
            return new ErrorResponse("Client not found", 404);
        }
        else{
            HashMap<String, Object> map = new HashMap<>();
            map.put("data",loginClient);
            return new SuccessResponse("client found", 200, map );
        }
    }



    public Object addParrainage(String parrainePhone, String parrainPhone){

        // Find the LoginClient by its phone
        LoginClient loginparrain = loginClientRepository.findByUsername(parrainPhone);

        if (loginparrain == null) {
            return new ErrorResponse("parrain not found", 404);
        }

        // Find the LoginClient by its phone
        LoginClient loginParraine = loginClientRepository.findByUsername(parrainePhone);

        if (loginParraine == null) {
            return new ErrorResponse("parraine not found", 404);
        }

        if(loginparrain.equals(loginParraine)){
            return new ErrorResponse("parrainage already exist", 404);
        }


        Parrainage parrainnage = parrainageRepository.findByParrainAndParrainee(loginparrain.getClient(),loginParraine.getClient());

        if (parrainnage != null) {
            return new ErrorResponse("parrainage already exist", 404);
        }

        Parrainage parrainage = new Parrainage();
        parrainage.setParrain(loginparrain.getClient());
        parrainage.setParrainee(loginParraine.getClient());
        parrainage.setParrainDetails("ras");
        parrainage.setParrainMontantPaye(0);
        parrainage.setParrainPaye("0");
        parrainageRepository.save(parrainage);


        // mise à jour de l'id de l'agence du nouveau
        Client clientParraine =  loginParraine.getClient();
        clientParraine.setIdAgence(loginparrain.getClient().getIdAgence());
        clientRepository.save(clientParraine);


        HashMap<String, Object> map = new HashMap<>();
        return new SuccessResponse("parrainage added", 200, map );

    }


    public Object fetchClientByCodeParrainage(String code) {

        ParrainCode parrainCode = parrainageCodeRepository.findByCodeParrainage(code);

        if ( parrainCode == null ) {
            return new ErrorResponse("Client not found", 404);
        }else{
            // Find the LoginClient by its ID
            Client client = parrainCode.getClient();
            HashMap<String, Object> map = new HashMap<>();
            map.put("data",client);
            return new SuccessResponse("client found", 200, map );
        }

    }


    @Transactional
    public Object  sendEmailValiderClient(Long idLoginClient) {

        // fetch login client object
        LoginClient loginClient = loginClientRepository.findById(idLoginClient).orElse(null);
        HashMap<String, Object> map = new HashMap<>();
        // return error message if not found
        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        try {
            SendEmail.sendEmailValidationCode(
                    loginClient.getClient().getPrenoms(),
                    loginClient.getClient().getNom(),
                    loginClient.getClient().getId());
            return new SuccessResponse("send successful", 200, map );
        }catch (MessagingException e) {
            e.printStackTrace();
            return new ErrorResponse("not correct code", 404);
        }


    }

    // endpoint to add an email to client profil
    @Transactional
    public Object accountCreatedConfirm(Long idLoginClient) {

        // Find the LoginClient by its ID
        LoginClient loginClient = loginClientRepository.findById(idLoginClient).orElse(null);

        if (loginClient == null) {
            return new ErrorResponse("Client not found", 404);
        }

        try {
            SendEmail.sendAccountCreatedConfirmEmail (
                "onanajunior92@gmail.com",//loginClient.getClient().getEmail(),
                loginClient.getClient().getPrenoms(),
                String.valueOf(loginClient.getLogin())
            );
        }catch (MessagingException e) {
            e.printStackTrace();
        }

        HashMap<String, Object> map = new HashMap<>();
        return new SuccessResponse("email ", 200, map );
    }


}




