package com.ffii.lioner.modules.master.service;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.ffii.core.utils.BeanUtils;
import org.springframework.stereotype.Service;

import com.ffii.lioner.modules.common.SecurityUtils;
import com.ffii.lioner.modules.common.service.AuditLogService;
import com.ffii.lioner.modules.master.entity.PromotionChannel;
import com.ffii.lioner.modules.master.entity.PromotionChannelRepository;
import com.ffii.lioner.modules.master.req.UpdatePromotionChannelReq;
import com.ffii.core.exception.NotFoundException;
import com.ffii.core.support.AbstractBaseEntityService;
import com.ffii.core.support.JdbcDao;
import com.ffii.core.utils.JsonUtils;
import com.ffii.core.utils.Params;

import jakarta.persistence.Table;

@Service
public class PromotionChannelService extends AbstractBaseEntityService<PromotionChannel, Long, PromotionChannelRepository> {

	private AuditLogService auditLogService;

	public PromotionChannelService(JdbcDao jdbcDao, PromotionChannelRepository repository, AuditLogService auditLogService) {
		super(jdbcDao, repository);
		this.auditLogService = auditLogService;
	}

	public Map<String,Object> getAuditLogObject(Map<String,Object> req){
		StringBuilder sql = new StringBuilder("SELECT"
			+ " pc.id,    "
			+ " pc.created,    "
			+ " pc.createdBy AS createdById,    "
			+ " u1.name AS createdBy,    "
			+ " pc.version,    "
			+ " pc.modified,    "
			+ " pc.modifiedBy AS modifiedById,    "
			+ " u2.name AS modifiedBy, "
			+ " pc.deleted, "
			+ " pc.name "
			+ " FROM promotion_channel pc   "
			+ " LEFT JOIN `user` u1 ON u1.id = pc.createdBy     "
			+ " LEFT JOIN `user` u2 ON u2.id = pc.modifiedBy      "
			+ " WHERE pc.id = :id    "
		);

		return jdbcDao.queryForMap(sql.toString(), req).get();
	}

	public List<Map<String,Object>> getNameList(){
		StringBuilder sql = new StringBuilder("SELECT"
			 + " pc.id, "
			 + " pc.name  "
			 + " FROM promotion_channel pc    "
			 + " WHERE pc.deleted = FALSE  "
		);

		return jdbcDao.queryForList(sql.toString());
	}

	public Integer getIdByName(String name) {
        StringBuilder sql = new StringBuilder("SELECT"
			+ " pc.id "
			+ " FROM promotion_channel pc  "
			+ " WHERE pc.deleted = FALSE"
			+ " AND pc.name = :name "
        );
        
        return jdbcDao.queryForInt(sql.toString(), Map.of("name", name));
    }

	public void markDeleteWithAuditLog (PromotionChannel instance){
		//=====GET OLD AUDIT LOG=====//
		String tableName = instance.getClass().getAnnotation(Table.class).name();
		StringBuilder sql = new StringBuilder("SELECT * FROM " + tableName + " WHERE id = :id");
		Map<String,Object> oldValueObject = new HashMap<String,Object>();
		Map<String,Object> newValueObject = new HashMap<String,Object>();
		
		if (instance != null && instance.getId() != null && instance.getId() > 0) {
			Map<String,Object> input = Map.of("id", instance.getId());
			Map<String,Object> logData= getAuditLogObject(input);
			oldValueObject = logData;
		}
		//=====GET OLD AUDIT LOG=====//
		markDelete(instance.getId());
		
		//=====GET NEW AUDIT LOG=====//
		if (instance != null && instance.getId() != null && instance.getId() > 0) {
			Map<String,Object> input = Map.of("id", instance.getId());
			Map<String,Object> logData= getAuditLogObject(input);
			newValueObject = logData;
		}


		if(auditLogService.compareMaps(newValueObject,oldValueObject).size() != 0 ||
			auditLogService.compareMaps(oldValueObject,newValueObject).size() != 0
		){
			auditLogService.save(
				tableName,
				instance.getId(),
				instance.getName(),
				SecurityUtils.getUser() != null ? SecurityUtils.getUser().get().getId() : null,
				new Date(),
				JsonUtils.toJsonString(auditLogService.compareMaps(newValueObject,oldValueObject)),
				JsonUtils.toJsonString(auditLogService.compareMaps(oldValueObject,newValueObject)));
		}
		//=====GET NEW AUDIT LOG=====//
	}

	public PromotionChannel saveOrUpdate(UpdatePromotionChannelReq req) {
		PromotionChannel instance;
		if(req.getId()>0){
			instance = find(req.getId()).get();
		}
		else{
			instance = new PromotionChannel();
		}
		//=====GET OLD AUDIT LOG=====//
		String tableName = instance.getClass().getAnnotation(Table.class).name();
		StringBuilder sql = new StringBuilder("SELECT * FROM " + tableName + " WHERE id = :id");
		Map<String,Object> oldValueObject = new HashMap<String,Object>();
		Map<String,Object> newValueObject = new HashMap<String,Object>();
		
		if (instance != null && instance.getId() != null && instance.getId() > 0) {
			Map<String,Object> input = Map.of("id", instance.getId());
			Map<String,Object> logData= getAuditLogObject(input);
			oldValueObject = logData;
		}
		//=====GET OLD AUDIT LOG=====//

		BeanUtils.copyProperties(req,instance);
		instance = save(instance);

		//=====GET NEW AUDIT LOG=====//
		if (instance != null && instance.getId() != null && instance.getId() > 0) {
			Map<String,Object> input = Map.of("id", instance.getId());
			Map<String,Object> logData= getAuditLogObject(input);
			newValueObject = logData;
		}


		if(auditLogService.compareMaps(newValueObject,oldValueObject).size() != 0 ||
			auditLogService.compareMaps(oldValueObject,newValueObject).size() != 0
		){
			auditLogService.save(
				tableName,
				instance.getId(),
				instance.getName(),
				SecurityUtils.getUser() != null ? SecurityUtils.getUser().get().getId() : null,
				new Date(),
				JsonUtils.toJsonString(auditLogService.compareMaps(newValueObject,oldValueObject)),
				JsonUtils.toJsonString(auditLogService.compareMaps(oldValueObject,newValueObject)));
		}
		//=====GET NEW AUDIT LOG=====//

		return instance;
	}

	public List<Map<String,Object>> listSubPromotionChannel(Map<String, Object> args){
		StringBuilder sql = new StringBuilder("SELECT"
			+ " sd.id, "
			+ " sd.name "
			+ " FROM PromotionChannel d  "
			+ " LEFT JOIN sub_PromotionChannel sd on sd.PromotionChannelId = d.id "
			+ " WHERE d.id = :id "
		);

		sql.append(" ORDER BY sd.id");

		return jdbcDao.queryForList(sql.toString(), args);
	}

	public List<Map<String,Object>> list(Map<String, Object> args){
		StringBuilder sql = new StringBuilder("SELECT"
            + " pc.id, "
            + " pc.name "
            + " FROM promotion_channel pc  "
            + " WHERE pc.deleted = FALSE  "
		);

		if (args != null) {
			if (args.containsKey(Params.ID)) sql.append(" AND pc.id = :id");
			if (args.containsKey(Params.NAME)) sql.append(" AND pc.name LIKE :name");
		}
		sql.append(" ORDER BY pc.name asc");

		return jdbcDao.queryForList(sql.toString(), args);
	}

	public List<Map<String,Object>> listChannelCombo(Map<String, Object> args){
		StringBuilder sql = new StringBuilder("SELECT"
            + " pc.id, "
			+ " pc.id as `key`, "
            + " pc.name as label"
            + " FROM promotion_channel pc "
            + " WHERE pc.deleted = FALSE "
		);

		sql.append(" ORDER BY pc.name asc");

		return jdbcDao.queryForList(sql.toString(), args);
	}

	public Map<String,Object> getChannelById(Map<String, Object> args){
		StringBuilder sql = new StringBuilder("SELECT"
            + " pc.id, "
			+ " pc.id as `key`, "
            + " pc.name as label"
            + " FROM promotion_channel pc "
            + " WHERE pc.deleted = FALSE "
			+ " AND pc.id = :id"
		);

		sql.append(" ORDER BY pc.name asc");

		return jdbcDao.queryForMap(sql.toString(), args).get();
	}

	public boolean isNameTaken(String name, Long id) {
        StringBuilder sql = new StringBuilder("SELECT"
            + " Count(pc.id) "
            + " FROM promotion_channel pc  "
            + " WHERE pc.deleted =FALSE  "
            + " AND pc.name = :name "
			+ " AND pc.id != :id"
        );
        
        return jdbcDao.queryForBoolean(sql.toString(), Map.of("name", name, "id", id));
    }
}

