package com.example.demo.service.impl;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
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.ErrorObj;
import com.example.demo.common.FilterResponse;
import com.example.demo.common.PageDetails;
import com.example.demo.common.PageResponse;
import com.example.demo.dto.DspCreateDTO;
import com.example.demo.dto.DspDeleteDTO;
import com.example.demo.dto.DspFilterEntity;
import com.example.demo.dto.DspFilterRequest;
import com.example.demo.dto.DspResponseDTO;
import com.example.demo.dto.DspUpdateDTO;
import com.example.demo.entity.Configurations;
import com.example.demo.entity.Dsp;
import com.example.demo.redisentity.DspRedis;
import com.example.demo.repository.ConfigurationRepo;
import com.example.demo.repository.DspRepository;
import com.example.demo.service.DspService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import redis.clients.jedis.Jedis;

@Service
public class DspServiceImpl implements DspService {

	@Autowired
	private DspRepository repo;

	@Autowired
	private ConfigurationRepo configRepo;

	@Autowired
	private Jedis jedis;

	@Override
	public APIResponse createdsp(DspCreateDTO create) throws JsonProcessingException {
		APIResponse api = new APIResponse();
		Dsp dsp = new Dsp();
		dsp.setAdExchange_name(create.getAdexchange_name());
		dsp.setBid_auction_type(create.getBid_auction_type());
		dsp.setEmail(create.getEmail());
		dsp.setRtb_mode(create.getRtb_mode());
		
		ObjectMapper mapper = new ObjectMapper();
		String srcstring = mapper.writeValueAsString(create.getParams());
        dsp.setParams(srcstring);
		
        String src = mapper.writeValueAsString(create.getVersion());
		dsp.setVersion(src);
		
        dsp.setStatus(1);
		dsp.setCreated_at(LocalDateTime.now());
		dsp.setUpdated_at(LocalDateTime.now());
		dsp.setCreated_by(create.getCreated_by());
		repo.save(dsp);

		DspRedis dspredis = new DspRedis();

		dspredis.setAdexchange_id(dsp.getAdexchange_id());
		UUID id = dspredis.getAdexchange_id();
		String id_str = id.toString();

		dspredis.setAdexchange_name(dsp.getAdExchange_name());
		String name_str = dspredis.getAdexchange_name();

		dspredis.setEmail(dsp.getEmail());
		String email_str = dspredis.getEmail();

		dspredis.setVersion(dsp.getVersion());
		String version_str = dspredis.getVersion();

		dspredis.setBid_auction_type(dsp.getBid_auction_type());
		String bid_auction_type_str = dspredis.getBid_auction_type();
		
		dspredis.setParams(dsp.getParams());
		String params_str = dspredis.getParams();

		dspredis.setRtb_mode(dsp.getRtb_mode());
		int rtb_mode = dspredis.getRtb_mode();
		String rtb_mode_str = Integer.toString(rtb_mode);

		dspredis.setStatus(dsp.getStatus());
		int status = dspredis.getStatus();
		String status_str = Integer.toString(status);

		dspredis.setCreated_at(dsp.getCreated_at());
		LocalDateTime created_at = dsp.getCreated_at();

		String[] arr = new String[2];

		arr[0] = created_at.toString();

		arr[1] = created_at.format(DateTimeFormatter.ofPattern("hh:mm:ss a", Locale.ENGLISH));
		String created_at_str = Arrays.toString(arr);

		dspredis.setCreated_by(dsp.getCreated_by());
		UUID created_by = dspredis.getCreated_by();
		String created_by_str = created_by.toString();

		dspredis.setUpdated_at(dsp.getUpdated_at());
		LocalDateTime updated_at = dsp.getUpdated_at();

		String[] arr1 = new String[2];

		arr1[0] = updated_at.toString();

		arr1[1] = updated_at.format(DateTimeFormatter.ofPattern("hh:mm:ss a", Locale.ENGLISH));
		String updated_at_str = Arrays.toString(arr1);

		String key = "Dsp_" + dsp.getAdexchange_id();
		Map<String, String> map = new HashMap<>();
		map.put("adexchange_id", id_str);
		map.put("adexchange_name", name_str);
		map.put("email", email_str);
		map.put("version", version_str);
		map.put("rtb_mode", rtb_mode_str);
		map.put("bid_auction_type", bid_auction_type_str);
		map.put("params", params_str);
		map.put("status", status_str);
		map.put("created_at", created_at_str);
		map.put("created_by", created_by_str);
		map.put("updated_at", updated_at_str);
		jedis.hmset(key, map);

		api.setData(dsp);
		api.setMessage("Dsp Created Successfully");
		api.setMsgCode("DSP CREATED SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse updatedsp(DspUpdateDTO update, UUID adexchange_id) throws JsonProcessingException {
		APIResponse api = new APIResponse();
		Dsp dsp = repo.findById(adexchange_id).orElse(null);
		if (dsp == null) {
			ErrorObj err = new ErrorObj();
			err.setCode("Id Not Found In Database");
			api.setError(err);
			api.setMessage("Adexchange Id Not Found");
			api.setMsgCode("ADEXCHANGE ID NOT FOUND");
			return api;
		}
		dsp.setAdExchange_name(update.getAdexchange_name());
		dsp.setBid_auction_type(update.getBidauction_type());
		dsp.setEmail(update.getEmail());
		dsp.setRtb_mode(update.getRtb_mode());
		dsp.setStatus(1);
		ObjectMapper mapper = new ObjectMapper();
		String srcstring = mapper.writeValueAsString(update.getParams());
        dsp.setParams(srcstring);
        
        String src = mapper.writeValueAsString(update.getVersion());
		dsp.setVersion(src);

        dsp.setUpdated_at(LocalDateTime.now());
		dsp.setUpdated_by(update.getUpdated_by());
		repo.save(dsp);

		DspRedis dspredis = new DspRedis();

		dspredis.setAdexchange_id(dsp.getAdexchange_id());
		UUID id = dspredis.getAdexchange_id();
		String id_str = id.toString();

		dspredis.setAdexchange_name(dsp.getAdExchange_name());
		String name_str = dspredis.getAdexchange_name();

		dspredis.setEmail(dsp.getEmail());
		String email_str = dspredis.getEmail();

		dspredis.setVersion(dsp.getVersion());
		String version_str = dspredis.getVersion();

		dspredis.setBid_auction_type(dsp.getBid_auction_type());
		String bid_auction_type_str = dspredis.getBid_auction_type();
		
		dspredis.setParams(dsp.getParams());
		String params_str = dspredis.getParams();

		dspredis.setRtb_mode(dsp.getRtb_mode());
		int rtb_mode = dspredis.getRtb_mode();
		String rtb_mode_str = Integer.toString(rtb_mode);

		dspredis.setStatus(dsp.getStatus());
		int status = dspredis.getStatus();
		String status_str = Integer.toString(status);

		dspredis.setCreated_at(dsp.getCreated_at());
		LocalDateTime created_at = dsp.getCreated_at();

		String[] arr = new String[2];

		arr[0] = created_at.toString();

		arr[1] = created_at.format(DateTimeFormatter.ofPattern("hh:mm:ss a", Locale.ENGLISH));
		String created_at_str = Arrays.toString(arr);

		dspredis.setCreated_by(dsp.getCreated_by());
		UUID created_by = dspredis.getCreated_by();
		String created_by_str = created_by.toString();

		dspredis.setUpdated_at(dsp.getUpdated_at());
		LocalDateTime updated_at = dsp.getUpdated_at();

		String[] arr1 = new String[2];

		arr1[0] = updated_at.toString();

		arr1[1] = updated_at.format(DateTimeFormatter.ofPattern("hh:mm:ss a", Locale.ENGLISH));
		String updated_at_str = Arrays.toString(arr1);

		dspredis.setUpdated_by(dsp.getUpdated_by());
		UUID updated_by = dspredis.getUpdated_by();
		String updated_by_str = updated_by.toString();

		String key = "Dsp_" + dsp.getAdexchange_id();
		Map<String, String> map = new HashMap<>();
		map.put("adexchange_id", id_str);
		map.put("adexchange_name", name_str);
		map.put("email", email_str);
		map.put("version", version_str);
		map.put("rtb_mode", rtb_mode_str);
		map.put("bid_auction_type", bid_auction_type_str);
		map.put("params",params_str);
		map.put("status", status_str);
		map.put("created_at", created_at_str);
		map.put("created_by", created_by_str);
		map.put("updated_at", updated_at_str);
		map.put("updated_by", updated_by_str);
		jedis.hmset(key, map);

		api.setData(dsp);
		api.setMessage("Dsp Update Successfully");
		api.setMsgCode("DSP UPDATE SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse getbyId(UUID adexchange_id) {
		APIResponse api = new APIResponse();
		Dsp dsp = repo.findById(adexchange_id).orElse(null);
		if (dsp == null) {
			ErrorObj err = new ErrorObj();
			err.setCode("Id Not Found In Database");
			api.setError(err);
			api.setMessage("Adexchange Id Not Found");
			api.setMsgCode("ADEXCHANGE ID NOT FOUND");
			return api;
		}
		DspResponseDTO response = MapToDTO(dsp);
		api.setData(response);
		api.setMessage("Dsp Details Get Successfully");
		api.setMsgCode("DSP DETAILS GET SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse getall() {
		APIResponse api = new APIResponse();
		List<Dsp> dsp = repo.findAll();
		List<DspResponseDTO> response = dsp.stream().map(use -> MapToDTO(use)).collect(Collectors.toList());
		api.setData(response);
		api.setMessage("List Of Dsp Successfully");
		api.setMsgCode("LIST OF DSP SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse blockdsp(UUID adexchange_id) {
		APIResponse api = new APIResponse();
		Dsp dsp = repo.findById(adexchange_id).orElse(null);
		dsp.setStatus(0);
		repo.save(dsp);

		DspRedis dspredis = new DspRedis();

		dspredis.setStatus(dsp.getStatus());
		int status = dspredis.getStatus();
		String status_str = Integer.toString(status);

		String key = "Dsp_" + dsp.getAdexchange_id();
		Map<String, String> map = new HashMap<>();
		map.put("status", status_str);
		jedis.hmset(key, map);

		api.setData(dsp);
		api.setMessage("Dsp Blocked Successfully");
		api.setMsgCode("DSP BLOCKED SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse unblockdsp(UUID adexchange_id) {
		APIResponse api = new APIResponse();
		Dsp dsp = repo.findById(adexchange_id).orElse(null);
		dsp.setStatus(1);
		repo.save(dsp);

		DspRedis dspredis = new DspRedis();

		dspredis.setStatus(dsp.getStatus());
		int status = dspredis.getStatus();
		String status_str = Integer.toString(status);

		String key = "Dsp_" + dsp.getAdexchange_id();
		Map<String, String> map = new HashMap<>();
		map.put("status", status_str);
		jedis.hmset(key, map);

		api.setData(dsp);
		api.setMessage("Dsp UnBlocked Successfully");
		api.setMsgCode("DSP UNBLOCKED SUCCESSFULLY");
		return api;
	}

	private DspResponseDTO MapToDTO(Dsp dsp) {
		DspResponseDTO response = new DspResponseDTO();
		response.setAdexchange_id(dsp.getAdexchange_id());
		response.setAdexchange_name(dsp.getAdExchange_name());
		response.setBid_auction_type(dsp.getBid_auction_type());
		response.setParams(dsp.getParams());
		response.setEmail(dsp.getEmail());
		response.setRtb_mode(dsp.getRtb_mode());
		response.setVersion(dsp.getVersion());
		response.setCreated_by(dsp.getCreated_by());
		List<Configurations> allObj = configRepo.findAll();
		Configurations config = allObj.get(0);
		DateTimeFormatter newYorkDateFormatter = DateTimeFormatter.ofPattern(config.getConfigValue());
		String arr = newYorkDateFormatter.format(ZonedDateTime.of(dsp.getCreated_at(), ZoneId.of("UTC-4")));
		response.setCreated_at(arr);
		String arr1 = newYorkDateFormatter.format(ZonedDateTime.of(dsp.getUpdated_at(), ZoneId.of("UTC-4")));
		response.setUpdated_at(arr1);
		response.setUpdated_by(dsp.getUpdated_by());
		if (dsp.getDeleted_at() != null) {
			String arr2 = newYorkDateFormatter.format(ZonedDateTime.of(dsp.getDeleted_at(), ZoneId.of("UTC-4")));
			response.setDeleted_at(arr2);
		}
		response.setDeleted_by(dsp.getDeleted_by());
		response.setIs_deleted(dsp.getIs_deleted());
		return response;
	}

	@Override
	public APIResponse deletedsp(DspDeleteDTO delete) {
		APIResponse api = new APIResponse();

		Dsp dsp = repo.findById(delete.getAdexchange_id()).orElse(null);
		dsp.setIs_deleted(1);
		dsp.setDeleted_at(LocalDateTime.now());
		dsp.setDeleted_by(delete.getDeleted_by());
		repo.save(dsp);

		DspRedis dspredis = new DspRedis();

		dspredis.setIs_deleted(dsp.getIs_deleted());
		int is_deleted = dspredis.getIs_deleted();
		String is_deleted_str = Integer.toString(is_deleted);

		dspredis.setDeleted_at(dsp.getDeleted_at());
		LocalDateTime deleted_at = dsp.getDeleted_at();

		String[] arr1 = new String[2];

		arr1[0] = deleted_at.toString();

		arr1[1] = deleted_at.format(DateTimeFormatter.ofPattern("hh:mm:ss a", Locale.ENGLISH));
		String deleted_at_str = Arrays.toString(arr1);

		dspredis.setDeleted_by(dsp.getDeleted_by());
		UUID deleted_by = dspredis.getDeleted_by();
		String deleted_by_str = deleted_by.toString();

		String key = "Dsp_" + dsp.getAdexchange_id();
		Map<String, String> map = new HashMap<>();
		map.put("is_deleted", is_deleted_str);
		map.put("deleted_at", deleted_at_str);
		map.put("deleted_by", deleted_by_str);
		jedis.hmset(key, map);

		api.setData(dsp);
		api.setMessage("Dsp_Deleted_Successfully");
		api.setMsgCode("DSP_DELETED_SUCCESSFULLY");
		return api;
	}

	@Override
	public FilterResponse list(DspFilterRequest filter) {
		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<Dsp> dsp = null;
			List<DspResponseDTO> dto = null;
			dsp = repo.findAll();
			dto = dsp.stream().map(dt1 -> MapToDTO(dt1)).collect(Collectors.toList());
			api.setData(dto);
			return api;
		}

		if (filter.getPages() == null) {
			PageDetails pageing2 = new PageDetails();

			pageable = null;

			List<Dsp> dsp = null;
			List<DspResponseDTO> dto = null;
			int ResponseCount;
			dsp = repo.findAll();
			dto = dsp.stream().map(dt1 -> MapToDTO(dt1)).collect(Collectors.toList());
			DspFilterEntity dspFilter = filter.getFilter();
			List<UUID> dspIdList = dsp.stream().map(ds -> ds.getAdexchange_id()).collect(Collectors.toList());
			List<Dsp> filteredList = repo.getallDetails(dspFilter.getName(), dspFilter.getStatus(),
					dspFilter.getIs_deleted(), dspIdList);
			List<UUID> filteredIdList = filteredList.stream().map(ids -> ids.getAdexchange_id())
					.collect(Collectors.toList());
			ResponseCount = repo.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<Dsp> dspListWithPage = repo.getFilteredListwithoutPage(filteredIdList, pageable).getContent();
			dto = dspListWithPage.stream().map(dspRes -> MapToDTO(dspRes)).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<DspResponseDTO> dspResList = null;

		// set 2 if filterRequest Page details not null

		int ResponseCount = 0;
		if (filter.getFilter() == null) {
			Page<Dsp> dsp = null;
			dsp = repo.findAll(pageable);

			List<UUID> dspIdList = dsp.stream().map(dsps -> dsps.getAdexchange_id()).collect(Collectors.toList());
			ResponseCount = repo.getResultCount(dspIdList);
			dsp = repo.getFilteredListwithoutPage(dspIdList, pageable);

			List<Dsp> ResContent = dsp.getContent();
			dspResList = ResContent.stream().map(dspRes -> MapToDTO(dspRes)).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(dspResList);
			api.setPage(pageRes);
			api.setMessage("DspList_With_Filter_2");
			api.setMsgCode("DSPLIST_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<Dsp> dsp = null;
		dsp = repo.findAll();

		DspFilterEntity dspFilter = filter.getFilter();
		List<UUID> dspIdList = dsp.stream().map(ds -> ds.getAdexchange_id()).collect(Collectors.toList());
		List<Dsp> filteredList = repo.getallDetails(dspFilter.getName(), dspFilter.getStatus(),
				dspFilter.getIs_deleted(), dspIdList);
		List<UUID> filteredIdList = filteredList.stream().map(ids -> ids.getAdexchange_id())
				.collect(Collectors.toList());
		ResponseCount = repo.getResultCount(filteredIdList);
		List<Dsp> dspFilteredContent = repo.getFilteredList(filteredIdList, pageable).getContent();
		dspResList = dspFilteredContent.stream().map(dspRes -> MapToDTO(dspRes)).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(dspResList);
		api.setPage(pageRes);
		api.setMessage("Filtered List of Dsp");
		api.setMsgCode("FILTERED_LIST_OF_DSP");

		return api;

	}
}
