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.SiteCreateDTO;
import com.example.demo.dto.SiteDeleteDTO;
import com.example.demo.dto.SiteFilter;
import com.example.demo.dto.SiteFilterEntity;
import com.example.demo.dto.SiteResponseDTO;
import com.example.demo.dto.SiteUpdateDTO;
import com.example.demo.entity.Configurations;
import com.example.demo.entity.Site;
import com.example.demo.redisentity.SiteRedis;
import com.example.demo.repository.ConfigurationRepo;
import com.example.demo.repository.SiteRepository;
import com.example.demo.service.SiteService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import redis.clients.jedis.Jedis;

@Service
public class SiteServiceImpl implements SiteService {

	@Autowired
	private SiteRepository repo;

	@Autowired
	private Jedis jedis;

	@Autowired
	private ConfigurationRepo configrepo;

	@Override
	public APIResponse createSite(SiteCreateDTO create) throws JsonProcessingException {
		APIResponse api = new APIResponse();
		Site site = new Site();
		site.setName(create.getName());
		site.setSite_url(create.getSite_url());
		site.setPlatform(create.getPlatform());
		site.setAppBundle_url(create.getAppbundle_url());
		site.setDomain(create.getDomain());
		ObjectMapper mapper = new ObjectMapper();
		String srcstring = mapper.writeValueAsString(create.getCategories());
		site.setCategory(srcstring);

		String category = mapper.writeValueAsString(create.getBlocked_category());
		site.setBlocked_category(category);

		site.setiTune_id(create.getItune_id());
		site.setCreated_at(LocalDateTime.now());
		site.setUpdated_at(LocalDateTime.now());
		site.setCreated_by(create.getCreated_by());
		site.setUpdated_at(LocalDateTime.now());
		repo.save(site);

		SiteRedis redis = new SiteRedis();

		redis.setSite_id(site.getSite_id());
		UUID site_id = redis.getSite_id();
		String site_id_str = site_id.toString();

		redis.setName(site.getName());
		String name_str = redis.getName();

		redis.setSite_url(site.getSite_url());
		String site_url_str = redis.getSite_url();

		redis.setPlatform(site.getPlatform());
		String platform_str = redis.getPlatform();

		redis.setAppbundle_url(site.getAppBundle_url());
		String appbundle_str = redis.getAppbundle_url();

		redis.setCategories(site.getCategory());
		String categories_str = redis.getCategories();

		String domain_str = null;
		if (site.getDomain() != null) {
			redis.setDomain(site.getDomain());
			domain_str = redis.getDomain();
		}

		String blocked_category_str = null;
		if (site.getBlocked_category() != null) {
			redis.setBlocked_category(site.getBlocked_category());
			blocked_category_str = redis.getBlocked_category();
		}

		redis.setItune_id(site.getiTune_id());
		String itune_id_str = redis.getItune_id();

		redis.setCreated_at(site.getCreated_at());
		LocalDateTime created_at = redis.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);

		redis.setCreated_by(site.getCreated_by());
		UUID created_by = redis.getCreated_by();
		String created_by_str = created_by.toString();

		redis.setUpdated_at(site.getUpdated_at());
		LocalDateTime updated_at = redis.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 update_at_str = Arrays.toString(arr1);

		String key = "Site_" + site.getSite_id();
		Map<String, String> map = new HashMap<>();
		map.put("site_id", site_id_str);
		map.put("name", name_str);
		map.put("site_url", site_url_str);
		map.put("appbundle_url", appbundle_str);
		map.put("platform", platform_str);
		map.put("categories", categories_str);
		if (blocked_category_str != null) {
			map.put("blocked_category", blocked_category_str);
		}
		if (domain_str != null) {
			map.put("domain", domain_str);
		}
		map.put("iTune_id", itune_id_str);
		map.put("created_at", created_at_str);
		map.put("created_by", created_by_str);
		map.put("updated_at", update_at_str);
		jedis.hmset(key, map);

		api.setData(site);
		api.setMessage("Site_Created_Successfully");
		api.setMsgCode("SITE_CREATED_SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse updateSite(SiteUpdateDTO update, UUID site_id) throws JsonProcessingException {
		APIResponse api = new APIResponse();
		Site site = repo.findById(site_id).orElse(null);
		if (site == null) {
			ErrorObj err = new ErrorObj();
			err.setCode("Given Site_Id Not Present In Database");
			api.setError(err);
			api.setMessage("Site Not Present In Database");
			api.setMsgCode("SITE NOT PRESENT IN DATABASE");
			return api;
		}
		site.setName(update.getName());
		site.setSite_url(update.getSite_url());
		site.setAppBundle_url(update.getAppbundle_url());
		site.setPlatform(update.getPlatform());
		site.setDomain(update.getDomain());

		ObjectMapper mapper = new ObjectMapper();
		String srcstring = mapper.writeValueAsString(update.getCategories());
		site.setCategory(srcstring);

		String category = mapper.writeValueAsString(update.getBlocked_category());
		site.setBlocked_category(category);

		site.setiTune_id(update.getItune_id());
		site.setUpdated_at(LocalDateTime.now());
		site.setUpdated_by(update.getUpdated_by());
		repo.save(site);

		SiteRedis redis = new SiteRedis();

		redis.setSite_id(site.getSite_id());
		UUID site_id1 = redis.getSite_id();
		String site_id_str = site_id1.toString();

		redis.setName(site.getName());
		String name_str = redis.getName();

		redis.setSite_url(site.getSite_url());
		String site_url_str = redis.getSite_url();

		redis.setPlatform(site.getPlatform());
		String platform_str = redis.getPlatform();

		redis.setAppbundle_url(site.getAppBundle_url());
		String appbundle_str = redis.getAppbundle_url();

		redis.setCategories(site.getCategory());
		String categories_str = redis.getCategories();

		String domain_str = null;
		if (site.getDomain() != null) {
			redis.setDomain(site.getDomain());
			domain_str = redis.getDomain();
		}

		String blocked_category_str = null;
		if (site.getBlocked_category() != null) {
			redis.setBlocked_category(site.getBlocked_category());
			blocked_category_str = redis.getBlocked_category();
		}

		redis.setItune_id(site.getiTune_id());
		String itune_id_str = redis.getItune_id();

		redis.setCreated_at(site.getCreated_at());
		LocalDateTime created_at = redis.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);

		redis.setCreated_by(site.getCreated_by());
		UUID created_by = redis.getCreated_by();
		String created_by_str = created_by.toString();

		redis.setUpdated_at(site.getUpdated_at());
		LocalDateTime updated_at = redis.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 update_at_str = Arrays.toString(arr1);

		redis.setUpdated_by(site.getUpdated_by());
		UUID updated_by = redis.getUpdated_by();
		String updated_by_str = updated_by.toString();

		String key = "Site_" + site.getSite_id();
		Map<String, String> map = new HashMap<>();
		map.put("site_id", site_id_str);
		map.put("name", name_str);
		map.put("site_url", site_url_str);
		map.put("appbundle_url", appbundle_str);
		map.put("platform", platform_str);
		map.put("categories", categories_str);
		if (blocked_category_str != null) {
			map.put("blocked_category", blocked_category_str);
		}
		if (domain_str != null) {
			map.put("domain", domain_str);
		}
		map.put("iTune_id", itune_id_str);
		map.put("created_at", created_at_str);
		map.put("created_by", created_by_str);
		map.put("updated_at", update_at_str);
		map.put("updated_by", updated_by_str);
		jedis.hmset(key, map);

		api.setData(site);
		api.setMessage("Site Updated Successfully");
		api.setMsgCode("SITE UPDATED SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse deleteSite(SiteDeleteDTO delete) {
		APIResponse api = new APIResponse();

		Site site = repo.findById(delete.getSite_id()).orElse(null);
		site.setIs_deleted(1);
		site.setDeleted_at(LocalDateTime.now());
		site.setDeleted_by(delete.getDeleted_by());
		repo.save(site);

		SiteRedis redis = new SiteRedis();

		redis.setIs_deleted(site.getIs_deleted());
		int is_deleted = redis.getIs_deleted();
		String is_deleted_str = Integer.toString(is_deleted);

		redis.setDeleted_at(site.getDeleted_at());
		LocalDateTime deleted_at = redis.getDeleted_at();

		String[] arr = new String[2];

		arr[0] = deleted_at.toString();

		arr[1] = deleted_at.format(DateTimeFormatter.ofPattern("hh:mm:ss a", Locale.ENGLISH));
		String deleted_at_str = Arrays.toString(arr);

		redis.setDeleted_by(site.getDeleted_by());
		UUID deleted_by = redis.getDeleted_by();
		String deleted_by_str = deleted_by.toString();

		String key = "Site_" + site.getSite_id();
		Map<String, String> map = new HashMap<String, String>();
		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.setMessage("Site Deleted Successfully");
		api.setMsgCode("SITE DELETED SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse getbyid(UUID site_id) {
		APIResponse api = new APIResponse();

		Site site = repo.findById(site_id).orElse(null);
		SiteResponseDTO response = MapToDto(site);
		api.setData(response);
		api.setMessage("Site Get Successfully");
		api.setMsgCode("SITE GET SUCCESSFULLY");
		return api;
	}

	@Override
	public APIResponse getall() {
		APIResponse api = new APIResponse();
		List<Site> site = repo.findAll();
		List<SiteResponseDTO> response = site.stream().map(dto -> MapToDto(dto)).collect(Collectors.toList());
		api.setData(response);
		api.setMessage("Site List Get Successfully");
		api.setMsgCode("SITE LIST GET SUCCESSFULLY");
		return api;
	}

	private SiteResponseDTO MapToDto(Site site) {
		SiteResponseDTO response = new SiteResponseDTO();
		response.setSite_id(site.getSite_id());
		response.setName(site.getName());
		response.setSite_url(site.getSite_url());
		response.setAppbundle_url(site.getAppBundle_url());
		response.setPlatform(site.getPlatform());
		response.setCategories(site.getCategory());
		response.setDomain(site.getDomain());
		response.setBlocked_category(site.getBlocked_category());
		response.setItune_id(site.getiTune_id());

		List<Configurations> allconfig = configrepo.findAll();
		Configurations obj = allconfig.get(0);
		DateTimeFormatter newYorkDateFormatter = DateTimeFormatter.ofPattern(obj.getConfigValue());
		String created_at = newYorkDateFormatter.format(ZonedDateTime.of(site.getCreated_at(), ZoneId.of("UTC-4")));
		response.setCreated_at(created_at);
		response.setCreated_by(site.getCreated_by());

		String updated_at = newYorkDateFormatter.format(ZonedDateTime.of(site.getUpdated_at(), ZoneId.of("UTC-4")));
		response.setUpdated_at(updated_at);
		response.setUpdated_by(site.getUpdated_by());

		if (site.getDeleted_at() != null) {
			String deleted_at = newYorkDateFormatter.format(ZonedDateTime.of(site.getDeleted_at(), ZoneId.of("UTC-4")));
			response.setDeleted_at(deleted_at);
		}
		response.setIs_deleted(site.getIs_deleted());
		response.setDeleted_by(site.getDeleted_by());
		return response;
	}

	@Override
	public FilterResponse list(SiteFilterEntity 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<Site> site = null;
			List<SiteResponseDTO> dto = null;
			site = repo.findAll();
			dto = site.stream().map(dt1 -> MapToDto(dt1)).collect(Collectors.toList());
			api.setData(dto);
			api.setMessage("List_Of_Sites");
			api.setMsgCode("LIST_OF_SITES");
			return api;
		}

		if (filter.getPages() == null) {
			PageDetails pageing2 = new PageDetails();

			pageable = null;

			List<Site> site = null;
			List<SiteResponseDTO> dto = null;
			int ResponseCount;
			site = repo.findAll();
			dto = site.stream().map(dt1 -> MapToDto(dt1)).collect(Collectors.toList());
			SiteFilter SiteFilter = filter.getFilter();
			List<UUID> SiteIdList = site.stream().map(camp -> camp.getSite_id()).collect(Collectors.toList());
			System.out.println("site list get successfully " + SiteIdList);
			List<Site> filteredList = repo.getallDetails(SiteFilter.getName(), SiteFilter.getCategories(),
					SiteFilter.getIs_deleted(), SiteIdList);
			System.out.println("Sitets :" + filteredList);
			List<UUID> filteredIdList = filteredList.stream().map(ids -> ids.getSite_id()).collect(Collectors.toList());
			System.out.println("sites :" + filteredIdList);
			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<Site> SiteListWithPage = repo.getFilteredListwithoutPage(filteredIdList, pageable).getContent();
			dto = SiteListWithPage.stream().map(site1 -> MapToDto(site1)).collect(Collectors.toList());

			PageResponse pageRes = new PageResponse();
			pageRes.setTotalCount(ResponseCount);
			pageRes.setPageSize(10);
			pageRes.setTotalCount(ResponseCount);
			api.setPage(pageRes);
			api.setData(dto);
			api.setMessage("List_Of_new_sites");
			return api;
		}
		List<SiteResponseDTO> CampignResList = null;

		// set 2 if filterRequest Page details not null

		int ResponseCount = 0;
		if (filter.getFilter() == null) {
			Page<Site> site = null;
			site = repo.findAll(pageable);

			List<UUID> CampignIdList = site.stream().map(camUni -> camUni.getSite_id()).collect(Collectors.toList());
			ResponseCount = repo.getResultCount(CampignIdList);
			site = repo.getFilteredListwithoutPage(CampignIdList, pageable);

			List<Site> ResContent = site.getContent();
			CampignResList = 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(CampignResList);
			api.setPage(pageRes);
			api.setMessage("SiteList_With_Filter_2");
			api.setMsgCode("SITELIST_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<Site> site = null;
		site = repo.findAll();

		SiteFilter siteFilter = filter.getFilter();
		List<UUID> SiteIdList = site.stream().map(cam -> cam.getSite_id()).collect(Collectors.toList());
		List<Site> filteredList = repo.getallDetails(siteFilter.getName(), siteFilter.getCategories(),
				siteFilter.getIs_deleted(), SiteIdList);
		List<UUID> filteredIdList = filteredList.stream().map(ids -> ids.getSite_id()).collect(Collectors.toList());
		ResponseCount = repo.getResultCount(filteredIdList);
		List<Site> campignFilteredContent = repo.getFilteredList(filteredIdList, pageable).getContent();
		CampignResList = 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(CampignResList);
		api.setPage(pageRes);
		api.setMessage("Filtered List of Sites");
		api.setMsgCode("FILTERED_LIST_OF_SITES");

		return api;

	}
}
