package com.style24.core.biz.thirdparty;

import java.util.ArrayList;
import java.util.List;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.style24.core.biz.dao.SsgDirectMessageDao;
import com.style24.core.biz.dao.TscAnswerPhaseDao;
import com.style24.core.support.env.TscConstants;
import com.style24.persistence.domain.AnswerPhase;
import com.style24.persistence.domain.SsgDirectMessage;

import lombok.extern.slf4j.Slf4j;

import com.gagaframework.web.parameter.GagaMap;
import com.gagaframework.web.util.GagaStringUtil;

/**
 * 신세계아이앤씨 SSG 모듈을 이용한 카카오알림톡 Sender
 * 
 * @author gagamel
 * @since 2020. 11. 9
 */
@Component
@Slf4j
public class SsgKakaoSender {

	// 발신프로필키
	private String profile = "95ed449aa61c05fb613253e740cceb7d3b5d0a64";

	// 발신자전화번호
	private String callbackTelNo;

	private String domainUrl;

	@Autowired
	private Environment env;

	@Autowired
	private TscAnswerPhaseDao ansPhaseDao;

	@Autowired
	private SsgDirectMessageDao dmDao;

	// 알림톡 답변일련번호
	public enum KakaoAnswerSq {
		JoinCongrat(1010),			// 회원가입축하 안내
		CertNoSend(1011),			// 인증번호발송 안내
		TempPasswd(1012),			// 임시비밀번호발급 안내
		OtoAnswer(1013),			// 1:1문의답변등록 안내
		DormantExpect(1014),		// 휴면계정전환예정 안내

		CardOrderComplete(1020),	// 주문완료-신용카드 안내
		BtOrderComplete(1021),		// 주문완료-계좌이체 안내
		VaOrderComplete(1022),		// 주문완료-무통장 안내
		VaDepositRequest(1023),		// 무통장입금요청 안내
		VaDepositConfirm(1024),		// 무통장입금확인 안내
		CardCancelRefund(1025),		// 주문취소 및 환불 안내-신용카드
		AtCancelRefund(1026),		// 주문취소 및 환불 안내-계좌이체
		VaCancelRefund(1027),		// 주문취소 및 환불 안내-무통장

		SoldoutExpect(1030),		// 품절예정안내
		CardCancelBySoldout(1031),	// 품절에 의한 주문취소 안내-신용카드
		AtCancelBySoldout(1032),	// 품절에 의한 주문취소 안내-계좌이체
		VaCancelBySoldout(1033),	// 품절에 의한 주문취소 안내-무통장

		GoodsSend(1040),			// 상품 발송 안내
		ExchGoodsSend(1041),		// 교환 상품 발송 안내

		ExchRequestComplete(1050),	// 교환 신청 완료 안내
		RtnRequestCompleted(1051),	// 반품 신청 완료 안내
		WithdrawDelay(1060),		// 회수처리 지연 안내
		ReviewWrite(1070),			// 상품평 작성 안내
		BasicLms(1071);				// 기본안내

		private Integer value;

		private KakaoAnswerSq(Integer value) {
			this.value = value;
		}

		public Integer value() {
			return value;
		}
	}

	@PostConstruct
	public void init() {
		domainUrl = env.getProperty("domain.front");
		callbackTelNo = TscConstants.CALLCENTER_TEL_NO;

		log.debug("\n\n---- SsgKakaoSender initialization started ----");
		log.debug("profile: [{}]", profile);
		log.debug("callbackTelNo: [{}]", callbackTelNo);
		log.debug("domainUrl: [{}]", domainUrl);
		log.debug("\n--- SsgKakaoSender initialization completed ----\n");
	}

	/**
	 * 카카오알림톡 발송
	 * @param ansSq - 답변일련번호
	 * @param dm - 메시지 정보
	 * @param replaceInfo - 메시지내용 중 대체할 정보
	 * @author gagamel
	 * @since 2020. 11. 9
	 */
	@Transactional("shopTxnManager")
	public void send(Integer ansSq, SsgDirectMessage dm, GagaMap replaceInfo) {
		// 답변문구 조회
		AnswerPhase ansPhase = this.getAnswerPhase(ansSq, replaceInfo);

		dm.setFyellowid(profile);
		dm.setFkkosubject(ansPhase.getAnsTitle());
		dm.setFtemplatekey(String.valueOf(ansSq));
		dm.setFmessage(ansPhase.getAnsContent());

		// kkoresendtype(재발송유형)이 "SMS"일 때만 kkoresendmsg(재발송메시지)에 값 설정
		// "LMS"일 때는 fmessage(메시지본문) 값으로 발송되며 kkoresendmsg(재발송메시지)에는 값을 넣으면 안 된다.
		if (dm.getFkkoresendtype().equals("SMS")) {
			dm.setFkkoresendmsg(ansPhase.getAnsContent());
		}

		dm.setFcallback(callbackTelNo);

		// 버튼생성
//		if (StringUtils.isNotBlank(dm.getButtonNm())) {
//			JSONObject button = new JSONObject();
//			button.put("name", dm.getButtonNm());
//			button.put("type", "WL");
//			button.put("url_mobile", domainUrl + dm.getButtonUrl());
//
//			JSONObject jsonData = new JSONObject();
//			jsonData.put("button", button);
//
//			JSONArray jsonArray = new JSONArray();
//			jsonArray.add(button);
//
//			dm.setFkkobutton(jsonArray.toString());
//		}

		// 카카오 알림톡 발송
		dmDao.createKakao(dm);
	}

	/**
	 * SMS 발송
	 * @param ansSq - 답변일련번호
	 * @param dm - 메시지 정보
	 * @param replaceInfo - 메시지내용 중 대체할 정보
	 * @author gagamel
	 * @since 2020. 11. 9
	 */
	@Transactional("shopTxnManager")
	public void sendSms(Integer ansSq, SsgDirectMessage dm, GagaMap replaceInfo) {
		// 답변문구 조회
		AnswerPhase ansPhase = this.getAnswerPhase(ansSq, replaceInfo);
		dm.setFmessage(ansPhase.getAnsContent());
		dm.setFcallback(callbackTelNo);
		dmDao.createSms(dm);
	}

	/**
	 * LMS 발송
	 * @param ansSq - 답변일련번호
	 * @param dm - 메시지 정보
	 * @param replaceInfo - 메시지내용 중 대체할 정보
	 * @author gagamel
	 * @since 2020. 11. 9
	 */
	@Transactional("shopTxnManager")
	public void sendLms(Integer ansSq, SsgDirectMessage dm, GagaMap replaceInfo) {
		// 답변문구 조회
		AnswerPhase ansPhase = this.getAnswerPhase(ansSq, replaceInfo);
		dm.setFsubject(ansPhase.getAnsTitle());
		dm.setFmessage(ansPhase.getAnsContent());
		dm.setFcallback(callbackTelNo);
		dmDao.createLms(dm);
	}

	/**
	 * 답변문구 조회
	 * @param ansSq - 답변일련번호
	 * @param replaceInfo - 메시지내용 중 대체할 정보
	 * @return
	 * @author gagamel
	 * @since 2020. 11. 9
	 */
	@Cacheable(value = "common", key = "'answerPhase-'.concat(#ansSq)")
	public AnswerPhase getAnswerPhase(Integer ansSq, GagaMap replaceInfo) {
		AnswerPhase ansPhase = ansPhaseDao.getAnswerPhase(ansSq);
		ansPhase.setAnsContent(GagaStringUtil.replace(this.mergeData(ansPhase.getAnsContent(), replaceInfo), "&gt;", ">"));
		return ansPhase;
	}

	/**
	 * 메시지 문자열 중에 '#{'로 시작하고 '}'로 끝나는 부분을 대체할 정보(replaceInfo)로 대체해 반환한다.
	 * @param message - 메시지 문자열
	 * @param replaceInfo - 알림톡 메시지 중 대체할 정보
	 * @return
	 * @author gagamel
	 * @date 2018. 1. 21.
	 */
	private String mergeData(String message, GagaMap replaceInfo) {
		List<String> keyList = getKeyList(message, "#{", "}");

		String key = "";
		String value = "";

		if (!keyList.isEmpty()) {
			for (int i = 0; i < keyList.size(); i++) {
				key = keyList.get(i);
				value = replaceInfo.getString(key);
				message = message.replace("#{" + key + "}", value);
			}
		}

		return message;
	}

	/**
	 * 입력 문자열로부터 시작 태그와 종료 태그 안의 key 목록을 반환한다.
	 * @param inputStr - 입력 문자열
	 * @param startTag - 시작 태그
	 * @param endTag - 종료 태그
	 * @return
	 * @author gagamel
	 * @date 2018. 1. 21.
	 */
	private List<String> getKeyList(String inputStr, String startTag, String endTag) {
		List<String> keyList = new ArrayList<>();

		String targetStr = inputStr;

		while (targetStr.indexOf(startTag) > -1) {
			int startPos = targetStr.indexOf(startTag) + startTag.length();
			int endPos = targetStr.indexOf(endTag, startPos);

			keyList.add(targetStr.substring(startPos, endPos));
			targetStr = targetStr.substring(endPos + endTag.length());
		}

		return keyList;
	}

}
