package com.example.demo.service.impl;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import com.example.demo.common.APIResponse;
import com.example.demo.common.FilterResponse;
import com.example.demo.common.PageDetails;
import com.example.demo.common.PageResponse;
import com.example.demo.dto.AddFundDTO;
import com.example.demo.dto.PaymentCreateDTO;
import com.example.demo.dto.PaymentFilterRequest;
import com.example.demo.dto.PaymentHistoryDTO;
import com.example.demo.dto.PaymentResponseDTO;
import com.example.demo.entity.Advertriser;
import com.example.demo.entity.ManageUser;
import com.example.demo.entity.Payment;
import com.example.demo.entity.PaymentFilterEntity;
import com.example.demo.entity.Roles;
import com.example.demo.redisentity.AdvertiserRedis;
import com.example.demo.repository.AdvertriserRepo;
import com.example.demo.repository.ManageUserRepository;
import com.example.demo.repository.PaymentRepository;
import com.example.demo.repository.RolesRepository;
import com.example.demo.service.PaymentService;

import redis.clients.jedis.Jedis;


@Service
public class PaymentServiceImpl implements PaymentService {

	@Autowired
	private ManageUserRepository userrepo;
	
	@Autowired
	private RolesRepository rolerepo;

	@Autowired
	private PaymentRepository paymentrepo;
	
	@Autowired
	private AdvertriserRepo addrepo;
	
	@Autowired
	private Jedis jedis;

	@Override
	public APIResponse addfund(AddFundDTO dto, UUID user_id) {
		APIResponse api = new APIResponse();
        ManageUser use = userrepo.findById(user_id).orElse(null);
        Roles role = rolerepo.findById(use.getRoleid()).orElse(null);
        if(role.getRoletype().equals("MASTER_ADMIN")) {
		Payment pay = new Payment();
		pay.setAmount(dto.getAmount());
		pay.setUser_id(user_id);
		pay.setAdvertiser_id(dto.getAdvertiser_id());
		pay.setDeposite_date(LocalDate.now());
		pay.setStatus(3);
		paymentrepo.save(pay);
		
		Advertriser add = addrepo.findById(dto.getAdvertiser_id()).orElse(null);
		add.setTotal_balance(add.getTotal_balance()+pay.getAmount());
		add.setDeposite_amount(add.getDeposite_amount()+pay.getAmount());
		addrepo.save(add);
		
		AdvertiserRedis advertiser = new AdvertiserRedis();
		
		advertiser.setTotal_balance(add.getTotal_balance());
		double total_balance = advertiser.getTotal_balance();
		String total_balance_str = Double.toString(total_balance);
		
		advertiser.setDeposite_amount(add.getDeposite_amount());
		double deposite_amount = advertiser.getDeposite_amount();
		String deposite_amount_str = Double.toString(deposite_amount);
		
		String key = "Advertiser_" + add.getAdvertiser_id();
		
		Map<String,String> map = new HashMap<>();
		map.put("total_balance", total_balance_str);
		map.put("deposite_amount",deposite_amount_str);
		
		jedis.hmset(key, map);
		
		api.setData(pay);
		api.setMessage("Fund Added Successfully");
		api.setMsgCode("FUND ADDED SUCCESSFULLY");

        }
        else {
        	Payment pay = new Payment();
    		pay.setAmount(dto.getAmount());
    		pay.setUser_id(user_id);
    		pay.setAdvertiser_id(dto.getAdvertiser_id());
    		pay.setDeposite_date(LocalDate.now());
    		pay.setStatus(0);
    		paymentrepo.save(pay);
    		
    		Advertriser add = addrepo.findById(dto.getAdvertiser_id()).orElse(null);
    		add.setTotal_balance(pay.getAmount());
    		addrepo.save(add);
    		
    		AdvertiserRedis advertiser = new AdvertiserRedis();
    		
    		advertiser.setTotal_balance(add.getTotal_balance());
    		double total_balance = advertiser.getTotal_balance();
    		String total_balance_str = Double.toString(total_balance);
    		
    		advertiser.setDeposite_amount(add.getDeposite_amount());
    		double deposite_amount = advertiser.getDeposite_amount();
    		String deposite_amount_str = Double.toString(deposite_amount);

    		String key = "Advertiser_" + add.getAdvertiser_id();
    		
    		Map<String,String> map = new HashMap<>();
    		map.put("total_balance", total_balance_str);
    		map.put("deposite_amount", deposite_amount_str);
    		jedis.hmset(key, map);
    		
    		api.setData(pay);
    		api.setMessage("Fund Added Successfully");
    		api.setMsgCode("FUND ADDED SUCCESSFULLY");

        }
//		PaymentRedis payment = new PaymentRedis();
//		
//		payment.setPayment_id(pay.getPayment_id());
//		UUID id = payment.getPayment_id();
//		String id_str = id.toString();
//		
//		payment.setDeposite_amount(pay.getAmount());
//		double amount = payment.getDeposite_amount();
//		String amount_str = Double.toString(amount);
//		
//		payment.setDeposite_date(pay.getDeposite_date());
//		LocalDate deposite_date = payment.getDeposite_date();
//		
//		String[] arr1 = new String[2];
//
//		arr1[0] = deposite_date.toString();
//
//		arr1[1] = deposite_date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH));
//		String deposite_date_str = Arrays.toString(arr1);
//		
//		String payment_type_str =null;
//		if(pay.getPayment_type()!=null) {
//		payment.setPayment_type(pay.getPayment_type());
//        payment_type_str = payment.getPayment_type();
//		}
//        payment.setSpend_amount(pay.getSpend_amount());
//        double spend_amount = payment.getSpend_amount();
//        String spend_amount_str = Double.toString(spend_amount);
//        
//        payment.setStatus(pay.getStatus());
//        int status = payment.getStatus();
//        String status_str = Integer.toString(status);
//        
//        payment.setUser_id(pay.getUser_id());
//        UUID user = payment.getUser_id();
//        String user_str = user.toString();
//        
//        String Key ="Payment_"+pay.getPayment_id();
//        
//        Map<String,String> map = new HashMap<>();
//        map.put("payment_id",id_str);
//        map.put("deposite_amount", amount_str);
//        map.put("deposite_date",deposite_date_str);
//        if(payment_type_str!=null) {
//        map.put("payment_type",payment_type_str);
//        }
//        map.put("spend_amount",spend_amount_str);
//        map.put("status", status_str);
//        map.put("user_id", user_str);
//        
//        jedis.hmset(Key, map);
		
		return api;
	}

	@Override
	public APIResponse getall() {
		APIResponse api = new APIResponse();
		List<Payment> add = paymentrepo.findAll();
		List<PaymentResponseDTO> pay = add.stream().map(add1 -> MapToDTO(add1)).collect(Collectors.toList());
		api.setData(pay);
		api.setMessage("List_Of_Payment");
		api.setMsgCode("LIST_OF_PAYMENT");
		return api;
	}

	private PaymentResponseDTO MapToDTO(Payment add) {
		PaymentResponseDTO response = new PaymentResponseDTO();
        
		response.setPayment_id(add.getPayment_id());
        response.setAmount(add.getAmount());
        if(add.getPayment_type()!=null) {
        response.setPayment_type(add.getPayment_type());
        }
        else {
        response.setPayment_type("Admin Deposit");
        }
        ManageUser use = userrepo.findById(add.getUser_id()).orElse(null);
        Roles role = rolerepo.findById(use.getRoleid()).orElse(null);
        if(role.getRoletype().equals("MASTER_ADMIN")) {
         response.setPayment_made_by("Admin");
        }
        else if(role.getRoletype().equals("ADVERTISER")){
         response.setPayment_made_by("Self");
        }
        else if(role.getRoletype().equals("PUBLISHER")) {
         response.setPayment_made_by("Self");
        }
        Advertriser adv = addrepo.findById(add.getAdvertiser_id()).orElse(null);
        response.setAdvertiser_name(adv.getAdvertiser_name());
        response.setEmail(adv.getEmail());
        
        if(add.getStatus()==0) {
        	response.setStatus("Pending");
        }
        else if(add.getStatus()==1) {
        	response.setStatus("Completed");
        }
        else if(add.getStatus()==2) {
        	response.setStatus("Rejected");
        }
        else if(add.getStatus()==3) {
        	response.setStatus("Self Approved");
        }
		LocalDate date = add.getDeposite_date();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		String date_str = date.format(formatter);
        response.setDate(date_str);
        
		return response;

	}

	@Override
	public APIResponse getbyid(UUID payment_id) {
		APIResponse api = new APIResponse();
		Payment add = paymentrepo.findById(payment_id).orElse(null);
		PaymentResponseDTO pay = MapToDTO(add);
		api.setData(pay);
		api.setMessage("Payment_Get_Successfully");
		api.setMsgCode("PAYMENT_GET_SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse createpayment(PaymentCreateDTO create, UUID advertiser_id) {
		APIResponse api  = new APIResponse();
		
		Payment pay = new Payment();
		pay.setAmount(create.getAmount());
		pay.setUser_id(advertiser_id);
		pay.setAdvertiser_id(advertiser_id);
		pay.setPayment_type(create.getPayment_type());
		pay.setDeposite_date(LocalDate.now());
		pay.setStatus(0);
		paymentrepo.save(pay);
		
		Advertriser add = addrepo.findById(advertiser_id).orElse(null);
		add.setTotal_balance(add.getTotal_balance()+pay.getAmount());
		add.setDeposite_amount(add.getDeposite_amount()+pay.getAmount());
		addrepo.save(add);

		AdvertiserRedis advertiser = new AdvertiserRedis();
		
		advertiser.setTotal_balance(add.getTotal_balance());
		double total_balance = advertiser.getTotal_balance();
		String total_balance_str = Double.toString(total_balance);
		
		advertiser.setDeposite_amount(add.getDeposite_amount());
		double deposite_amount = advertiser.getDeposite_amount();
		String deposite_amount_str = Double.toString(deposite_amount);

		
		String key = "Advertiser_" + add.getAdvertiser_id();
		
		Map<String,String> map = new HashMap<>();
		map.put("total_balance", total_balance_str);
		map.put("deposite_amount",deposite_amount_str);
		
		jedis.hmset(key, map);

		
//		PaymentRedis payment = new PaymentRedis();
//		
//		payment.setPayment_id(pay.getPayment_id());
//		UUID id = payment.getPayment_id();
//		String id_str = id.toString();
//		
//		payment.setDeposite_amount(pay.getAmount());
//		double deposite_amount = payment.getDeposite_amount();
//		String deposite_amount_str = Double.toString(deposite_amount);
//		
//		payment.setDeposite_date(pay.getDeposite_date());
//		LocalDate deposite_date = payment.getDeposite_date();
//		
//		String[] arr1 = new String[2];
//
//		arr1[0] = deposite_date.toString();
//
//		arr1[1] = deposite_date.format(DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.ENGLISH));
//		String deposite_date_str = Arrays.toString(arr1);
//
//		String payment_type_str = null;
//		if(pay.getPayment_type()!=null) {
//		payment.setPayment_type(pay.getPayment_type());
//		payment_type_str = payment.getPayment_type();
//		}
//		
//		payment.setSpend_amount(pay.getSpend_amount());
//		double spend_amount = payment.getSpend_amount();
//		String spend_amount_str = Double.toString(spend_amount);
//		
//		payment.setStatus(pay.getStatus());
//		int status = payment.getStatus();
//		String status_str = Integer.toString(status);
//		
//		payment.setUser_id(pay.getUser_id());
//		UUID user = payment.getUser_id();
//		String user_str = user.toString();
//		
//		String Key = "Payment_"+pay.getPayment_id();
//		
//		Map<String,String> map = new HashMap<>();
//		map.put("payment_id",id_str);
//		map.put("deposite_amount",deposite_amount_str);
//		map.put("deposite_date", deposite_date_str);
//		if(payment_type_str!=null) {
//		map.put("payment_type",payment_type_str);
//		}
//		map.put("spend_amount",spend_amount_str);
//		map.put("status", status_str);
//		map.put("user_id", user_str);
//		
//		jedis.hmset(Key, map);
		
		api.setData(pay);
		api.setMessage("Payment Created Successfully");
		api.setMsgCode("PAYMENT CREATED SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse ApprovePayment(UUID payment_id) {
		APIResponse api = new APIResponse();
		
		Payment pay = paymentrepo.findById(payment_id).orElse(null);
		pay.setStatus(1);
		paymentrepo.save(pay);
		
		Advertriser add = addrepo.findById(pay.getAdvertiser_id()).orElse(null);
		add.setTotal_balance(add.getTotal_balance()+pay.getAmount());
		addrepo.save(add);

		AdvertiserRedis advertiser = new AdvertiserRedis();
		
		advertiser.setTotal_balance(add.getTotal_balance());
		double total_balance = advertiser.getTotal_balance();
		String total_balance_str = Double.toString(total_balance);
		
		advertiser.setDeposite_amount(add.getDeposite_amount());
		double deposite_amount = advertiser.getDeposite_amount();
		String deposite_amount_str = Double.toString(deposite_amount);

		String key = "Advertiser_" + add.getAdvertiser_id();
		
		Map<String,String> map = new HashMap<>();
		map.put("total_balance", total_balance_str);
		map.put("deposite_amount",deposite_amount_str);
		
		jedis.hmset(key, map);

		
//		PaymentRedis payment = new PaymentRedis();
//		
//		payment.setStatus(pay.getStatus());
//		int status = payment.getStatus();
//		String status_str = Integer.toString(status);
//		
//		String Key ="Payment_"+pay.getPayment_id();
//		
//		Map<String,String> map = new HashMap<>();
//		map.put("status", status_str);
//		
//		jedis.hmset(Key, map);
		
		api.setData(pay);
		api.setMessage("Payment Approved Successfully");
		api.setMsgCode("PAYMENT APPROVED SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse RejectPayment(UUID payment_id) {
		APIResponse api = new APIResponse();
		
		Payment pay =paymentrepo.findById(payment_id).orElse(null);
		pay.setStatus(2);
		paymentrepo.save(pay);
		
//		PaymentRedis payment = new PaymentRedis();
//		
//		payment.setStatus(pay.getStatus());
//		int status = payment.getStatus();
//		String status_str = Integer.toString(status);
//		
//		String Key ="Payment_"+pay.getPayment_id();
//		
//		Map<String,String> map = new HashMap<>();
//		map.put("status",status_str);
//		
//		jedis.hmset(Key, map);
		
		api.setData(pay);
		api.setMessage("Payment Rejected");
		api.setMsgCode("Payment REJECTED");
		return api;
	}

	@Override
	public APIResponse paymenthistroy() {
		APIResponse api = new APIResponse();
		List<Payment> pay = paymentrepo.paymentamount();
		List<PaymentHistoryDTO> response = pay.stream().map(use->MapToDTO2(use)).collect(Collectors.toList());
		
		api.setData(response);
		api.setMessage("Payment History Get Successfully");
		api.setMsgCode("PAYMENT HISTROY GET SUCCESSFULLY");
		return api;
	}

	private PaymentHistoryDTO MapToDTO2(Payment pay) {
		PaymentHistoryDTO response = new PaymentHistoryDTO();
		
		LocalDate date = pay.getDeposite_date();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		String date_str = date.format(formatter);
        response.setDate(date_str);
        
        Advertriser add = addrepo.findById(pay.getAdvertiser_id()).orElse(null);
        response.setName(add.getAdvertiser_name());
        response.setEmail(add.getEmail());
        
        response.setDeposite_amount(pay.getAmount());
        response.setSpend_amount(pay.getSpend_amount());

		return response;
	}

	@Override
	public FilterResponse filterrequest(PaymentFilterRequest filter, UUID user_id) {
		FilterResponse api = new FilterResponse();

		String field = null, order = null;
		if (filter.getSort() != null && filter.getSort().size() == 1) {
			for (Map.Entry m : filter.getSort().entrySet()) {
				field = (String) m.getKey();
				order = (String) m.getValue();
			}
		} else {

		}

		PageDetails pageing = filter.getPages();
		Pageable pageable = null;

		if (filter.getFilter() == null && filter.getPages() == null) {

			List<Payment> payment = null;
			List<PaymentResponseDTO> dto = null;
			ManageUser user = userrepo.findById(user_id).orElse(null);
			Roles role = rolerepo.findById(user.getRoleid()).orElse(null);
			if (role.getRoletype().equals("MASTER_ADMIN")) {
				payment = paymentrepo.findAll();
			} else if (role.getRoletype().equals("PUBLISHER")) {
				payment = paymentrepo.findbyadvertiser(user_id);
			}
			dto = payment.stream().map(dt1 -> MapToDTO(dt1)).collect(Collectors.toList());
			api.setData(dto);
			api.setMessage("List_Of_Payment");
			api.setMsgCode("LIST_OF_PAYMENT");
			return api;
		}

		if (filter.getPages() == null) {
			PageDetails pageing2 = new PageDetails();

			pageable = null;

			List<Payment> payment = null;
			List<PaymentResponseDTO> dto = null;
			int ResponseCount;
			ManageUser user = userrepo.findById(user_id).orElse(null);
			Roles role = rolerepo.findById(user.getRoleid()).orElse(null);
			if (role.getRoletype().equals("MASTER_ADMIN")) {
				payment = paymentrepo.findAll();
			} else if (role.getRoletype().equals("PUBLISHER")) {
				payment = paymentrepo.findbyadvertiser(user_id);
			}
			dto = payment.stream().map(dt1 -> MapToDTO(dt1)).collect(Collectors.toList());
			PaymentFilterEntity paymentFilter = filter.getFilter();
			List<UUID> paymentIdList = payment.stream().map(pay->pay.getPayment_id()).collect(Collectors.toList());
			List<Payment> filteredList = paymentrepo.getallDetails(paymentFilter.getStatus(),paymentFilter.getPayment_type(),paymentIdList);
			List<UUID> filteredIdList = filteredList.stream().map(ids -> ids.getPayment_id()).collect(Collectors.toList());
			ResponseCount = paymentrepo.getResultCount(filteredIdList);
			if (ResponseCount == 0) {
				ResponseCount = 10;
			}
			if (filter.getSort() == null || filter.getSort().size() == 0) {

				pageable = (Pageable) PageRequest.of(0, ResponseCount, Sort.by("name"));
			} else {
				if (field.equals("") || order.equals("")) {
					pageable = (Pageable) PageRequest.of(0, ResponseCount, Sort.by("name"));

				}

				else if (order.equalsIgnoreCase("asc")) {
					pageable = (Pageable) PageRequest.of(0, ResponseCount, Sort.by(field));
				} else {
					pageable = (Pageable) PageRequest.of(0, ResponseCount, Sort.by(field).descending());
				}
			}

			List<Payment> paymentListWithPage = paymentrepo.getFilteredListwithoutPage(filteredIdList, pageable)
					.getContent();
			dto = paymentListWithPage.stream().map(payRes -> MapToDTO(payRes)).collect(Collectors.toList());

			PageResponse pageRes = new PageResponse();
			pageRes.setTotalCount(ResponseCount);
			pageRes.setPageSize(10);
			pageRes.setTotalCount(ResponseCount);
			api.setPage(pageRes);
			api.setData(dto);
			return api;
		}
		List<PaymentResponseDTO> paymentResList = null;

		// set 2 if filterRequest Page details not null

		int ResponseCount = 0;
		if (filter.getFilter() == null) {
			Page<Payment> payment = null;
			ManageUser user = userrepo.findById(user_id).orElse(null);
			Roles role = rolerepo.findById(user.getRoleid()).orElse(null);
			if (role.getRoletype().equals("MASTER_ADMIN")) {
				payment = paymentrepo.findAll(pageable);
			} else if (role.getRoletype().equals("PUBLISHER")) {
				payment = paymentrepo.findbypayment_id(user_id, pageable);
			}

			List<UUID> paymentIdList = payment.stream().map(camUni -> camUni.getPayment_id()).collect(Collectors.toList());
			ResponseCount = paymentrepo.getResultCount(paymentIdList);
			payment = paymentrepo.getFilteredListwithoutPage(paymentIdList, pageable);

			List<Payment> ResContent = payment.getContent();
			paymentResList = ResContent.stream().map(campignunitRes -> MapToDTO(campignunitRes))
					.collect(Collectors.toList());
			PageResponse pageRes = new PageResponse();
			pageRes.setTotalCount(ResponseCount);
			pageRes.setPageCount(pageing.getPageIndex());
			if (pageing.getPageSize() == 0) {
				pageRes.setPageSize(10);
			} else {
				pageRes.setPageSize(pageing.getPageSize());
			}
			api.setData(paymentResList);
			api.setPage(pageRes);
			api.setMessage("Payment_With_Filter_2");
			api.setMsgCode("PAYMENT_WITH_FILTER_2");
			return api;
		}

		if (filter.getSort() == null || filter.getSort().size() == 0) {
			if (pageing.getPageSize() == 0) {
				pageable = (Pageable) PageRequest.of(pageing.getPageIndex(), 10, Sort.by("name"));
			} else {
				pageable = (Pageable) PageRequest.of(pageing.getPageIndex(), pageing.getPageSize(), Sort.by("name"));
			}
		} else {
			if (field.equals("") || order.equals("")) {
				if (pageing.getPageSize() == 0) {
					pageable = (Pageable) PageRequest.of(pageing.getPageIndex(), 10, Sort.by("name"));
				} else {
					pageable = (Pageable) PageRequest.of(pageing.getPageIndex(), pageing.getPageSize(),
							Sort.by("name"));
				}
			}

			else if (order.equalsIgnoreCase("asc")) {
				if (pageing.getPageSize() == 0) {
					pageable = (Pageable) PageRequest.of(pageing.getPageIndex(), 10, Sort.by(field));
				} else {
					pageable = (Pageable) PageRequest.of(pageing.getPageIndex(), pageing.getPageSize(), Sort.by(field));
				}
			} else {
				if (pageing.getPageSize() == 0) {
					pageable = (Pageable) PageRequest.of(pageing.getPageIndex(), 10, Sort.by(field).descending());
				} else {
					pageable = (Pageable) PageRequest.of(pageing.getPageIndex(), pageing.getPageSize(),
							Sort.by(field).descending());
				}
			}
		}

		List<Payment> payment = null;
		ManageUser user = userrepo.findById(user_id).orElse(null);
		Roles role = rolerepo.findById(user.getRoleid()).orElse(null);
		if (role.getRoletype().equals("MASTER_ADMIN")) {
			payment = paymentrepo.findAll();
		} else if (role.getRoletype().equals("PUBLISHER")) {
			payment = paymentrepo.findbyadvertiser(user_id);
		}

		PaymentFilterEntity paymentFilter = filter.getFilter();
		List<UUID> paymentIdList = payment.stream().map(cam -> cam.getPayment_id()).collect(Collectors.toList());
		List<Payment> filteredList = paymentrepo.getallDetails(paymentFilter.getStatus(),paymentFilter.getPayment_type(),paymentIdList);
		List<UUID> filteredIdList = filteredList.stream().map(ids -> ids.getPayment_id()).collect(Collectors.toList());
		ResponseCount = paymentrepo.getResultCount(filteredIdList);
		List<Payment> campignFilteredContent = paymentrepo.getFilteredList(filteredIdList, pageable).getContent();
		paymentResList = campignFilteredContent.stream().map(campignRes -> MapToDTO(campignRes))
				.collect(Collectors.toList());

		PageResponse pageRes = new PageResponse();
		pageRes.setTotalCount(ResponseCount);
		pageRes.setPageCount(pageing.getPageIndex());
		if (pageing.getPageSize() == 0) {
			pageRes.setPageSize(10);
		} else {
			pageRes.setPageSize(pageing.getPageSize());
		}
		api.setData(paymentResList);
		api.setPage(pageRes);
		api.setMessage("Filtered List of Publisher");
		api.setMsgCode("FILTERED_LIST_OF_PUBLISHER");

		return api;
	}
}
