package com.style24.core.biz.thirdparty;

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

import javax.annotation.PostConstruct;

import org.apache.commons.lang3.StringUtils;
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.gagaframework.web.parameter.GagaMap;
import com.gagaframework.web.util.GagaStringUtil;
import com.google.gson.Gson;
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.Data;
import lombok.extern.slf4j.Slf4j;

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

	// 발신프로필키
	private String profile = "7b97ecfcd7fce4fff464105c2365869dee86887c";

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

	private String domainUrl;

	private String active;

	@Autowired
	private Environment env;

	@Autowired
	private TscAnswerPhaseDao ansPhaseDao;

	@Autowired
	private SsgDirectMessageDao dmDao;

	// 알림톡 답변일련번호
	public enum KakaoAnswerSq {
		JOIN_CONGRATS(1010),						// 회원가입축하 안내
		TEMP_PASSWD(1011),							// 임시비밀번호발급 안내
		CERT_NO_SEND(1012),							// 인증번호발송 안내
		DORMANT_EXPECT(1013),						// 휴면계정전환예정 안내
		PRIVACY_POLICY(1014),						// 개인정보 이용내역 안내
		MARKETING_AGREE(1015),						// 마케팅 수신동의 안내
		BIRTH_COUPON_NOTICE(1016),					// 생일 축하 안내
		GRADE_NOTICE(1017),							// 이달 등급안내
		GOODS_ASK_ANSWER(1018),						// 상품문의 답변 등록 안내
		ONE_TO_ONE_ANSWER(1019),					// 1:1문의답변등록 안내

		DORMANT_EXPECT_COMBACK(1020),				// 휴면/미접속자방어쿠폰안내
		REVIEW_WRITE(1023),							// 상품평 등록 안내
		GIFTCARD_EXTNC_EXPECT(1024),				// 상품권 소멸 예정 안내
		COUPON_EXTNC_EXPECT(1025),					// 쿠폰 소멸 예정안내
		POINT_EXTNC_EXPECT(1026),					// 포인트 소멸 예정안내
		GOODS_UNPURCHASED(1027),					// 미구매 상품 확인안내
		SHOPPING_BAG_DISCOUNT(1028),				// 쇼핑백 할인혜택 안내
		WISHLIST_DISCOUNT(1029),					// 위시리스트 할인혜택 안내

		ORDER_COMPLETE(1030),						// 주문완료 안내
		AT_ORDER_COMPLETE(1031),					// 주문완료-계좌이체 안내
		VA_ORDER_COMPLETE(1032),					// 주문완료-무통장 안내
		VA_DEPOSIT_REQUEST(1033),					// 무통장 입금 요청
		VA_DEPOSIT_CONFIRM(1034),					// 무통장 입금 확인 안내

		GOODS_SEND(1035),							// 상품 배송출발 안내

		CARD_CANCEL_REFUND(1036),					// 주문취소 및 환불 안내-신용카드
		NA_CANCEL_REFUND(1037),						// 주문취소 및 환불 안내-통신사
		AT_CANCEL_REFUND(1038),						// 주문취소 및 환불 안내-계좌이체
		VA_CANCEL_REFUND(1039),						// 주문취소 및 환불 안내-무통장
		ETC_CANCEL_REFUND(1057),					// 주문취소 및 환불 안내-페이코,네이버,카카오
		VA_CANCEL_NO_ACCOUNT_REFUND(1062),			// 주문취소 및 환불 안내-무통장(환불계좌X)
		VA_CANCEL_BEFORE_PAYMENT_REFUND(1063),		// 주문취소 및 환불 안내-무통장(입금전)

		//CARD_CANCEL_BY_SOLDOUT(1051),				// 품절 주문 취소 안내-신용카드
		NA_CANCEL_BY_SOLDOUT(1051),					// 품절 주문 취소 안내-통신사
		//AT_CANCEL_BY_SOLDOUT(1052),					// 품절 주문 취소 안내-계좌이체
		//VA_CANCEL_BY_SOLDOUT(1042),					// 품절 주문 취소 안내-무통장
		ETC_CANCEL_BY_SOLDOUT(1051),				// 품절 주문 취소 안내-페이코,네이버,카카오
		//VA_CANCEL_NO_ACCOUNT_BY_SOLDOUT(1061),		// 품절 주문 취소 안내-무통장(환불계좌X)
		//VA_CANCEL_BEFORE_PAYMENT_BY_SOLDOUT(1064),	// 품절 주문 취소 안내-무통장(입금전)
		
		
		CARD_CANCEL_BY_SOLDOUT(1040),				// 품절 주문 취소 안내-신용카드,페이코,네이버,카카오, 통신사  ST_067
		AT_CANCEL_BY_SOLDOUT(1041),					// 품절 주문 취소 안내-계좌이체			ST_068
		VA_CANCEL_BY_SOLDOUT(1042),					// 품절 주문 취소 안내-무통장				ST_069
		VA_CANCEL_NO_ACCOUNT_BY_SOLDOUT(1061),		// 품절 주문 취소 안내-무통장(환불계좌X)	ST_054
		VA_CANCEL_BEFORE_PAYMENT_BY_SOLDOUT(1071),	// 품절 주문 취소 안내-무통장(입금전)		ST_084
		ETC_EXTMALL_SOLDOUT(1051),					// 품절 주문 취소 안내-제휴몰				ST_038 
		ETC_EXTMALL_PART_SOLDOUT(1052),				// 품절 주문 취소 안내-제휴몰(부분)			ST_039

		GIFT_EXPIRATION_CANCEL(1058),				// 선물하기 취소

		EXCHANGE_REQUEST(1043),						// 교환 접수 안내
		RETURN_REQUEST(1044),						// 반품 접수 안내
		RETURN_COMPLETE(1045),						// 반품 완료 안내
		EXCHANGE_ADD_COST(1070),					// 추가 비용 발생 안내 - 교환
		RETURN_ADD_COST(1047),						// 추가 비용 발생 안내 - 반품
		WHITHDRAW_START(1048),						// 회수 시작 안내
		RETURN_CANCEL_CUSTOMER(1049),				// 반품 철회 안내 - 고객부재
		RETURN_CANCEL_ADDR(1050),					// 반품 철회 안내 - 주소불일치 
		EXCHANGE_CANCEL_CUSTOMER(1059),				// 교환 철회 안내 - 고객부재
		EXCHANGE_CANCEL_ADDR(1060),					// 교환 철회 안내 - 주소불일치

		EXTMALL_SOLDOUT(1065),						// 제휴몰 품절 주문 취소 안내
		EXTMALL_PART_SOLDOUT(1066),					// 제휴몰 품절 주문 취소 안내 - 부분

		GIFT_ARRIVED(1053),							// 선물 도착 안내
		GOODS_RESTOCK(1054),						// 재입고 안내
		APP_DOWNLOAD(1055),							// APP 다운
		BASIC_LMS(1056),
		BASIC_INFO_LMS(1080),						// [스타일24] 안내
		BASIC_INFO_EXT_LMS(1081);					// 제휴몰 - 대외용
		
		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;
		active = env.getProperty("spring.profiles.active");
		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(ansPhase.getKakaoCd());
		dm.setFmessage(ansPhase.getAnsContent());
		dm.setFcallback(callbackTelNo);

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

		// 버튼생성
		if (StringUtils.isNotBlank(ansPhase.getButtonNm())) {
			Button button = new Button();
			button.setName(ansPhase.getButtonNm());
			button.setType("WL");
			button.setUrl_pc(ansPhase.getButtonUrl());
			button.setUrl_mobile(ansPhase.getButtonUrl());
			
			// 2021.07.09 버튼 URL 공통 처리 전송값이 있으면 전송된 값 처리
			if (dm.getButtonUrl() == null || "".equals(dm.getButtonUrl())) {
				button.setUrl_pc(ansPhase.getButtonUrl());
				button.setUrl_mobile(ansPhase.getButtonUrl());
			} else {
				button.setUrl_pc(dm.getButtonUrl());
				button.setUrl_mobile(dm.getButtonUrl());
			}

			Collection<Button> buttonList = new ArrayList<>();
			buttonList.add(button);

			Gson gson = new Gson();
			dm.setFkkobutton("\"button\":" + gson.toJson(buttonList));

			// LMS도 SMS처럼 kkoresendmsg(재발송메시지)에 값을 설정해 처리할 수 있게 변경되었음.
			if (dm.getFkkoresendtype().equals("LMS")) {
				
				// 2021.07.09 버튼 URL 공통 처리 전송값이 있으면 전송된 값 처리
				if (dm.getButtonUrl() == null || "".equals(dm.getButtonUrl())) {
					dm.setFkkoresendmsg(ansPhase.getAnsContent() + "\n" + ansPhase.getButtonNm() + "\n" + ansPhase.getButtonUrl());
				} else {
					dm.setFkkoresendmsg(ansPhase.getAnsContent() + "\n" + ansPhase.getButtonNm() + "\n" + dm.getButtonUrl());
				}
			}
		}

		// 카카오 알림톡 발송
		if ("style".equals(active) || "locp".equals(active) || "stage".equals(active) || "brdg".equals(active)) {
			dmDao.createKakao(dm);
		} else {
			dmDao.createKakaoDev(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);
		if ("style".equals(active) || "locp".equals(active) || "stage".equals(active) || "brdg".equals(active)) {
			dmDao.createSms(dm);
		} else {
			dmDao.createSmsDev(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);
		if ("style".equals(active) || "locp".equals(active) || "stage".equals(active) || "brdg".equals(active)) {
			dmDao.createLms(dm);
		} else {
			dmDao.createLmsDev(dm);
		}
	}

	/**
	 * LMS 발송
	 * @param ansSq - 답변일련번호
	 * @param dm - 메시지 정보
	 * @param replaceInfo - 메시지내용 중 대체할 정보
	 * @author gagamel
	 * @since 2020. 11. 9
	 */
	@Transactional("shopTxnManager")
	public void sendLms3(Integer ansSq, SsgDirectMessage dm, GagaMap replaceInfo) {
		// 답변문구 조회
		AnswerPhase ansPhase = this.getAnswerPhase(ansSq, replaceInfo);
		dm.setFsubject(ansPhase.getAnsTitle());
		dm.setFmessage(ansPhase.getAnsContent());
		dm.setFcallback(replaceInfo.getString("callcenterTelNo"));
		if ("style".equals(active) || "locp".equals(active) || "stage".equals(active) || "brdg".equals(active)) {
			dmDao.createLms(dm);
		} else {
			dmDao.createLmsDev(dm);
		}
	}
	
	/**
	 * 답변문구 조회
	 * 		어드민의 "운영관리 > 사이트설정 > 답변문구관리" 화면에서 등록/수정 시 answerPhase 캐시를 삭제
	 * @param ansSq - 답변일련번호
	 * @param replaceInfo - 메시지내용 중 대체할 정보
	 * @return
	 * @author gagamel
	 * @since 2020. 11. 9
	 */
	@Cacheable(value = "answerPhase", key = "#ansSq")
	public AnswerPhase getAnswerPhase(Integer ansSq, GagaMap replaceInfo) {
		AnswerPhase ansPhase = ansPhaseDao.getAnswerPhase(ansSq);
		ansPhase.setAnsContent(GagaStringUtil.replace(this.mergeData(ansPhase.getAnsContent(), replaceInfo), "&gt;", ">"));
		ansPhase.setButtonUrl(GagaStringUtil.replace(this.mergeData(ansPhase.getButtonUrl(), replaceInfo), "&gt;", ">"));
		return ansPhase;
	}

	/**
	 * 답변문구 조회
	 *
	 * @param ansSq - 답변일련번호
	 * @param dm - Direct Message 정보
	 * @param replaceInfo - 메시지내용 중 대체할 정보
	 * @return SsgDirectMessage
	 * @author jsshin
	 * @since 2021. 07. 16
	 */
	public SsgDirectMessage getDiretMessage(Integer ansSq, SsgDirectMessage dm, GagaMap replaceInfo) {
		AnswerPhase ansPhase = this.getAnswerPhase(ansSq, replaceInfo);
		dm.setFyellowid(profile);
		dm.setFkkosubject(ansPhase.getAnsTitle());
		dm.setFtemplatekey(ansPhase.getKakaoCd());
		dm.setFmessage(ansPhase.getAnsContent());
		dm.setFcallback(callbackTelNo);

		// kkoresendtype(재발송유형)이 "SMS"일 때만 kkoresendmsg(재발송메시지)에 값 설정
		// "LMS"일 때는 fmessage(메시지본문) 값으로 발송되며 kkoresendmsg(재발송메시지)에는 값을 넣으면 안 된다.
		if (dm.getFkkoresendtype().equals("SMS")) {
			if (StringUtils.isBlank(dm.getFkkoresendmsg())) {
				dm.setFkkoresendmsg(ansPhase.getAnsContent());
			}
		}
				// 버튼생성
		if (StringUtils.isNotBlank(ansPhase.getButtonNm())) {
			Button button = new Button();
			button.setName(ansPhase.getButtonNm());
			button.setType("WL");
			button.setUrl_pc(ansPhase.getButtonUrl());
			button.setUrl_mobile(ansPhase.getButtonUrl());

			// 2021.07.09 버튼 URL 공통 처리 전송값이 있으면 전송된 값 처리
			if (dm.getButtonUrl() == null || "".equals(dm.getButtonUrl())) {
				button.setUrl_pc(ansPhase.getButtonUrl());
				button.setUrl_mobile(ansPhase.getButtonUrl());
			} else {
				button.setUrl_pc(dm.getButtonUrl());
				button.setUrl_mobile(dm.getButtonUrl());
			}

			Collection<Button> buttonList = new ArrayList<>();
			buttonList.add(button);

			Gson gson = new Gson();
			dm.setFkkobutton("\"button\":" + gson.toJson(buttonList));

			// LMS도 SMS처럼 kkoresendmsg(재발송메시지)에 값을 설정해 처리할 수 있게 변경되었음.
			if (dm.getFkkoresendtype().equals("LMS")) {

				// 2021.07.09 버튼 URL 공통 처리 전송값이 있으면 전송된 값 처리
				if (dm.getButtonUrl() == null || "".equals(dm.getButtonUrl())) {
					dm.setFkkoresendmsg(ansPhase.getAnsContent() + "\n" + ansPhase.getButtonNm() + "\n" + ansPhase.getButtonUrl());
				} else {
					dm.setFkkoresendmsg(ansPhase.getAnsContent() + "\n" + ansPhase.getButtonNm() + "\n" + dm.getButtonUrl());
				}
			}
		}
		return dm;
	}

	/**
	 * 메시지 문자열 중에 '#{'로 시작하고 '}'로 끝나는 부분을 대체할 정보(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;
	}

	@Data
	class Button {
		private String name;
		private String type;
		private String url_pc;
		private String url_mobile;
	}

}
