package nlib.col.service.impl;

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

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import nlib.cmm.service.NlibProperty;
import nlib.col.service.CartCookieVO;
import nlib.col.service.CartService;
import nlib.col.service.CollectionService;
import nlib.col.service.CollectionVO;
import nlib.util.StringUtil;

/**
 * <pre>
 * @Class Name : CartServiceImpl.java
 * 
 * @Description : 카트관련 기능 서비스 구현 클래스 
 * 
 * 
 * @프로젝트명: 지방문화원 통합자료관리시스템 구축사업 (2021)
 *
 * </pre>
 *
 * @ ------------    --------    ---------------------------
 * @ 수정일                     수정자             수정내용
 * @ ------------    --------    ---------------------------
 * @ 2021. 10. 5.    KNKIM       최초 생성
 *
 * 
 * @author 이씨플라자 * DIGITALSHIP KNKIM
 * @since 2021. 10. 5.
 * @version 1.0
 *
 */
@Service("cartService")
public class CartServiceImpl implements CartService
{
	private static final Logger log = LoggerFactory.getLogger(CartServiceImpl.class);
	
	// 비로그인회원의 카트정보 쿠키명 
	public static final String CART_COOKIE_NAME = NlibProperty.getString("cart.cookie.name");
	
	
	@Resource(name="cartDAO")
	private CartDAO cartDAO;
	
    @Resource(name = "collectionService")
    private CollectionService collectionService;
    
	/**
	 * (로그인자용) 로그인한 사용자의 카트 목록을 조회한다. 
	 * 
	 * @param mbInfoId
	 * @param cartDivCd
	 * @return
	 * @throws Exception
	 */
	public List<CollectionVO> listCartItems(String mbInfoId, String cartTypeCd) throws Exception {
		return cartDAO.listCartItems(mbInfoId, cartTypeCd);
	}
	
	/**
	 * (비로그인자용) 쿠키에서 카트 목록을 조회한다. 
	 * 
	 * @param request
	 * @param cartTypeCd
	 * @return
	 * @throws Exception
	 */
	public List<CollectionVO> listCartItemsFromCookie(HttpServletRequest request, HttpServletResponse response, String cartTypeCd) throws Exception {
		
		if(StringUtil.isEmpty(cartTypeCd)) return null;
		List<CollectionVO> list = new ArrayList<CollectionVO>();
		
		String targetCookieName = CART_COOKIE_NAME + cartTypeCd;
		
		// _NLIB_COOKIE1=:masterId:masterId:
		String cartStr = getCookie(request, targetCookieName);
		if(StringUtil.isEmpty(cartStr)) return null;
		
		String[] cartItemsStr = cartStr.split(":");
		for(String itemStr : cartItemsStr) {
			if(StringUtil.isEmpty(itemStr)) continue; 
			CollectionVO vo = CollectionVO.createWithMasterId(targetCookieName.substring(targetCookieName.length()-2), itemStr);
			vo.setMbCartId(vo.getMasterId()); // 비회원 쿠키 카트의 경우, 카트ID를 자료ID로 대체한다.
			if(vo != null) list.add(vo);
		}
		
		if(list.size() < 1) return null;
		
		return list;
	}
	
	/**
	 * (로그인자용) 카트 영역 구분코드를 변경한다. (대출 <-> 방문열람)
	 * 
	 * @param mbInfoId
	 * @param targetCartItems
	 * @return
	 * @throws Exception
	 */
	public String changeCartType(CollectionVO cartVO) throws Exception {
		if(cartVO == null || StringUtil.isEmpty(cartVO.getMbInfoId())) return "회원 정보가 없습니다.";
		if(StringUtil.isEmpty(cartVO.getSelItems())) return "변경할 대상 정보가 없습니다.";
		
		String checkResult = checkValidCartItems(cartVO.getCartTypeCd(), cartVO.getSelItems());
		if(checkResult != null) return checkResult;
		
		updateSelItemsForDB(cartVO);
		int resultCnt = cartDAO.changeCartType(cartVO);
			
		if(resultCnt > 0) return null;
		
		return "변경 처리에 실패하였습니다. 관리자에게 문의하여 주시기 바랍니다.";
	}
	
	/**
	 * (비로그인자용) 카트 영역 구분코드를 변경한다. (대출 <-> 방문열람)
	 * 
	 * @param request
	 * @param targetCartItems
	 * @return
	 * @throws Exception
	 */
	public String changeCartTypeToCookie(HttpServletRequest request, HttpServletResponse response, CollectionVO cartVO) throws Exception {
		
		if(cartVO == null) return "요청 정보가 없습니다.";
		if(StringUtil.isEmpty(cartVO.getSelItems())) return "변경할 대상 정보가 없습니다.";
		
		String checkResult = checkValidCartItems(cartVO.getCartTypeCd(), cartVO.getSelItems());
		if(checkResult != null) return checkResult;
		
		int totCnt = 0;
		int sucCnt = 0;
		int errCnt = 0;
		
		String addCartTypeCd = null;
		String delCartTypeCd = null;
		
		if("1".equals(cartVO.getCartTypeCd())) {
			addCartTypeCd = "1";
			delCartTypeCd = "2";
		} else if("2".equals(cartVO.getCartTypeCd())) {
			addCartTypeCd = "2";
			delCartTypeCd = "1";
		} else {
			return "카트 구분값 정보가 정확하지 않습니다.";
		}
		
		String[] masterIds = cartVO.getSelItems().split(",");
		String resultMsgAdd = null;
		String resultMsgDel = null;
		
		// 쿠키 카트 정보 가져오기 
		CartCookieVO cartCookie = getCartCookieInfo(request);
		
		for(int i=0; i<masterIds.length; i++) {
			if(StringUtil.isEmpty(masterIds[i])) continue;
			
			totCnt++;
			resultMsgAdd = cartCookie.addCartItem(addCartTypeCd, masterIds[i]);
			if(resultMsgAdd == null) {
				sucCnt++;
				resultMsgDel = cartCookie.removeCartItem(delCartTypeCd, masterIds[i]);
				if(resultMsgDel != null) log.error("changeCartTypeFromCookie removing > " + delCartTypeCd + "카트 " + masterIds[i] + " : 삭제오류  => " + resultMsgDel);
			} else {
				errCnt++;
				log.error("changeCartTypeFromCookie adding > " + addCartTypeCd + "카트 " + masterIds[i] + " : 추가 오류  => " + resultMsgAdd);
			}
				
		}
		
		if(sucCnt > 0) {
			String result = setCookieCart(response, cartCookie);
			if(result == null) {
				if(totCnt == sucCnt) return null;
				else return String.format("총 %d건의 자료 중 %d건에 대한 변경 처리가 정상적으로 처리되었습니다.", totCnt, sucCnt);
			} else {
				return result;
			}
		}
		
		return StringUtil.getString(resultMsgAdd, "") + StringUtil.getString(resultMsgDel, "");
	}
	
	/**
	 * (로그인자용) 카트에 추가한다. 
	 * 
	 * @param cartVO
	 * @return
	 * @throws Exception
	 */
	public String insertCartItem(CollectionVO cartVO) throws Exception {
		
		cartVO = checkValidCartItem(cartVO);
		
		if(cartVO.getResultCode().charAt(0) != 'S') return cartVO.getResultMessage();
		
		//-----------------------------------------------
		// 등록 처리  
		//-----------------------------------------------
		int resultCnt = cartDAO.insertCartItem(cartVO);
		
		if(resultCnt > 0) return null;
		
		return "등록 처리에 실패하였습니다. 관리자에게 문의하여 주시기 바랍니다.";
	}

	/**
	 * (비로그인자용) 카트에 추가한다. 
	 * 
	 * @param cartVO
	 * @return
	 * @throws Exception
	 */
	public String insertCartItemToCookie(HttpServletRequest request,  HttpServletResponse response, CollectionVO cartVO) throws Exception {

		cartVO = checkValidCartItem(cartVO);
		
		if(cartVO.getResultCode().charAt(0) != 'S') return cartVO.getResultMessage();
		

		//-----------------------------------------------
		// 등록 처리  
		//-----------------------------------------------
		
		// 쿠키 카트 정보 가져오기 
		CartCookieVO cartCookie = getCartCookieInfo(request);
		String result = cartCookie.addCartItem(cartVO.getCartTypeCd(), cartVO.getMasterId());
		
		if(result != null) return result;
		
		return setCookieCart(response, cartCookie);
	}
	
	/**
	 * (비로그인자용) 쿠키에서 카트 정보를 조회하여 CartCookieVO 생성하여 리턴한다. 
	 * 
	 * @param request
	 * @return
	 */
	public CartCookieVO getCartCookieInfo(HttpServletRequest request) {
		CartCookieVO cartCookieInfo = new CartCookieVO();
		cartCookieInfo.setRentValues(getCookie(request, CART_COOKIE_NAME + "1"));
		cartCookieInfo.setReadValues(getCookie(request, CART_COOKIE_NAME + "2"));
		
		return cartCookieInfo;
	}
	
	/**
	 * (비로그인자용) 쿠키 카트에 자료 항목을 추가한다. 
	 * 
	 * @param request
	 * @param response
	 * @param cartTypeCd
	 * @param masterId
	 * @return
	 */
	public String setCookieCart(HttpServletResponse response, CartCookieVO cartCookie) {

		if(response == null) return "쿠키를 저장할 Response 객체 정보가 없습니다.";
		if(cartCookie == null) return "쿠키에 저장할 카트정보가 없습니다.";
		
		setCookie(response, CART_COOKIE_NAME + "1", cartCookie.getRentValues());
		setCookie(response, CART_COOKIE_NAME + "2", cartCookie.getReadValues());
		
		return null;
	}

	/**
	 * (비로그인자용) 쿠키값을 설정한다. 
	 * 
	 * @param response
	 * @param name
	 * @param value
	 */
	public void setCookie(HttpServletResponse response, String name, String value) {
		Cookie cookie = new Cookie(name, value);
		cookie.setDomain(NlibProperty.getString("cart.cookie.domain"));
		cookie.setPath(NlibProperty.getString("cart.cookie.path"));
		response.addCookie(cookie);
	}
	
	/**
	 * (비로그인자용) 쿠키값을 가져온다.
	 * 
	 * @param request
	 * @param cookieName
	 * @return
	 */
	public String getCookie(HttpServletRequest request, String cookieName) {
		Cookie[] cookies = request.getCookies();
		
		if(cookies == null || cookies.length < 1) return null;
		if(StringUtil.isEmpty(cookieName)) return null;
		
		for(Cookie cookie : cookies) {
			if(cookieName.equalsIgnoreCase(cookie.getName())) {
				return cookie.getValue();
			}
		}
		
		return null;
	}


	/**
	 * 해당 자료가 대출/열람 카트 유형에 추가될 수 있는지 검증한다.  
	 * 
	 * @param String : null 정상
	 * @return
	 * @throws Exception
	 */
	public String checkValidCartItems(String cartTypeCd, String selItems) throws Exception {
		
		if(StringUtil.isEmpty(cartTypeCd)) return "카트 유형 정보가 존재하지 않습니다.";
		if(StringUtil.isEmpty(selItems)) return "대상 자료 정보가 존재하지 않습니다.";
		
		String masterIds[] = selItems.split(",");
		for(int i=0; i<masterIds.length; i++) {
			CollectionVO cartVO = CollectionVO.createWithMasterId(cartTypeCd, masterIds[i]);
			cartVO = checkValidCartItem(cartVO);
			
			if(cartVO.getResultCode().charAt(0) != 'S') return cartVO.getTitle() + "에 대한 유형변경은 불가합니다. 대출 또는 방문열람이 가능한 자료인지 확인바랍니다.";
		}
		
		return null;
	}
		
		
	/**
	 * 카트에 추가할 수 있는 자료인지 확인하고, 대출/열람 유형을 검증한다. 필요시 대출/열람 유형을 변경하고 리턴한다. 
	 * 
	 * @param cartVO
	 * @return
	 * @throws Exception
	 */
	public CollectionVO checkValidCartItem(CollectionVO cartVO) throws Exception {
		
		if(cartVO == null) return new CollectionVO("FCART00", "카트에 추가할 자료 정보가 없습니다.");
		
		//-----------------------------------------------
		// 기존에 등록된 자료인지 확인  
		//-----------------------------------------------
		int existCnt = cartDAO.countCartItem(cartVO);
		if(existCnt > 0) {
			cartVO.setResult("FCART01", "이미 카트에 등록된 자료입니다.");
			return cartVO;
		}
		
		//-----------------------------------------------
		// 해당 카트 구분값으로 등록가능한지 여부 체크 
		//-----------------------------------------------
		CollectionVO searchColVO = new CollectionVO();
		searchColVO.setMasterId(cartVO.getMasterId());
		searchColVO.setMngOrgCd(cartVO.getMngOrgCd());
		searchColVO.setTypeDivCd(cartVO.getTypeDivCd());
		searchColVO.setMbInfoId(cartVO.getMbInfoId());
		CollectionVO collectionVO = collectionService.getItemInfo(searchColVO);
		
		// 자료 상세 조회 성공한 경우 
		if(collectionVO.getResultCode().startsWith("S")) {
			
			cartVO.setTitle(collectionVO.getTitle());
			
			// 대출인 경우 
			if("1".equals(cartVO.getCartTypeCd())) {
				
				// 대출불가인 경우
				if("02".equals(collectionVO.getOperOutRangeCd())) { // 대출가능여부 확인 : 02 대출불가
					
					// 열람 가능인 경우 열람 처리 
					if(!"03".equals(collectionVO.getOperReadRangeCd())) {
						cartVO.setCartTypeCd("2"); // 대출가능하지 않으나 열람 가능한 경우, 열람으로 강제 변경
					} else {
						cartVO.setResult("FCART02", "대출 및 열람이 불가한 자료입니다.");
						return cartVO;
					}
				}
			}
			// 열람인 경우 
			else if("2".equals(cartVO.getCartTypeCd())) {
				
				// 열람불가인 경우 
				if("03".equals(collectionVO.getOperReadRangeCd())) { // 열람가능여부 확인 : 03 열람불가
					
					// 대출가능한 경우, 대출로 처리 
					if(!"02".equals(collectionVO.getOperOutRangeCd())) {
						cartVO.setCartTypeCd("1"); // 대출가능한 경우, 대출로 강제 변경 
					} else {
						cartVO.setResult("FCART03", "열람 및 대출이 불가한 자료입니다.");
						return cartVO;
					}
				}
				
			}
			// 카드유형구분이 없는 경우, 대출->열람 우선순위서 설정  
			else {
				if(!"02".equals(collectionVO.getOperOutRangeCd())) { // 대출가능여부 확인 : 02 대출불가
					cartVO.setCartTypeCd("1"); // 대출가능한 경우, 대출로 설정  
				} else if(!"03".equals(collectionVO.getOperReadRangeCd())) { // 열람가능여부 확인 : 03 열람불가
					cartVO.setCartTypeCd("2"); // 열람가능한 경우, 열람으로 설정
				} else {
					cartVO.setResult("FCART04", "대출 및 열람이 불가한 자료입니다.");
					return cartVO;
				}
			}
		}
		// 자료 상세 조회 실패한 경우, 처리결과 메시지를 리턴한다.
		else {
			cartVO.setResult("FCART05", collectionVO.getResultMessage());
			return cartVO;
		}
		
		cartVO.setResult("S", null);
		return cartVO;
		
	}
	
	/**
	 * (로그인자용) 카트에서 선택된 자료들을 삭제한다. 
	 * 
	 * @param targetCartItems
	 * @return
	 * @throws Exception
	 */
	public String deleteCartItems(CollectionVO cartVO) throws Exception {
		if(cartVO == null || StringUtil.isEmpty(cartVO.getMbInfoId())) return "회원 정보가 없습니다.";
		
		String selItems = cartVO.getSelItems();
		if(StringUtil.isEmpty(selItems)) return "삭제할 자료 정보가 없습니다.";
		
		updateSelItemsForDB(cartVO);
		int resultCnt = cartDAO.deleteCartItems(cartVO);
		
		if(resultCnt > 0) return null;
		return "변경 처리에 실패하였습니다. 관리자에게 문의하여 주시기 바랍니다.";
	}
	
	/**
	 * (비로그인자용) 카트에서 선택된 자료들을 삭제한다. 
	 * 
	 * @param targetCartItems
	 * @return
	 * @throws Exception
	 */
	public String deleteCartItemsFromCookie(HttpServletRequest request, HttpServletResponse response, CollectionVO cartVO) throws Exception {
	
		if(cartVO == null) return "요청 정보가 없습니다.";
		if(StringUtil.isEmpty(cartVO.getSelItems())) return "변경할 대상 정보가 없습니다.";
		
		int totCnt = 0;
		int sucCnt = 0;
		int errCnt = 0;
		
		String delCartTypeCd = cartVO.getCartTypeCd();
		
		if(!"1".equals(delCartTypeCd) && !"2".equals(delCartTypeCd)) {
			return "카트 구분값 정보가 정확하지 않습니다.";
		}
		
		// 쿠키 카트 정보 가져오기 
		CartCookieVO cartCookie = getCartCookieInfo(request);
		
		String[] masterIds = cartVO.getSelItems().split(",");
		String resultMsgDel = null;
		for(int i=0; i<masterIds.length; i++) {
			if(StringUtil.isEmpty(masterIds[i])) continue;
			
			totCnt++;
			resultMsgDel = cartCookie.removeCartItem(delCartTypeCd, masterIds[i]);
			if(resultMsgDel == null) {
				sucCnt++;
			} else {
				errCnt++;
				log.error("changeCartTypeFromCookie removing > " + delCartTypeCd + "카트 " + masterIds[i] + " : 삭제 오류  => " + resultMsgDel);
			}
		}
	
		if(sucCnt > 0) {
			String result = setCookieCart(response, cartCookie);
			if(result == null) {
				if(totCnt == sucCnt) return null;
				else return String.format("총 %d건의 자료 중 %d건에 대한 삭제가 정상적으로 처리되었습니다.", totCnt, sucCnt);
			} else {
				return result;
			}
		}
		
		return StringUtil.getString(resultMsgDel, "");
	}

	public void updateSelItemsForDB(CollectionVO cartVO) {

		if(cartVO == null || StringUtil.isEmpty(cartVO.getMbInfoId())) return;
		
		String selItems = cartVO.getSelItems();
		
		if(!selItems.startsWith("'")) {
			String[] items = selItems.split(",");
			String newSelItems = "";
			for(String item : items) {
				
				if(StringUtil.isEmpty(item)) continue;
				
				if(newSelItems.length() > 0) newSelItems += ",";
				
				newSelItems += "'" + item + "'";
			}
			cartVO.setSelItems(newSelItems);
		}
		
		log.debug("updateSelItemsForDB > " + cartVO.getSelItems());
	}

	/**
	 * 쿠키 카트(비로그인 상태의 카트정보) 존재하는 경우, 해당 사용자 카트(DB)로 등록한 후, 쿠키 카트 삭제한다.  
	 * 
	 * @param request
	 * @param response
	 * @return
	 * @throws Exception
	 */
	public int mergeCart(String mbInfoId, HttpServletRequest request, HttpServletResponse response) throws Exception {
	
		// 대출 카트
		String cartTypeCds[] = {"1", "2"};
		int mergeCnt = 0;
		
		for(String cartTypeCd : cartTypeCds) {
			List<CollectionVO> list = listCartItemsFromCookie(request, response, cartTypeCd);
			if(list == null || list.size() < 1) continue;
			
			for(CollectionVO item : list) {
				item.setCartTypeCd(cartTypeCd);
				item.setMbInfoId(mbInfoId);
				item.setRegId(mbInfoId);
				if(insertCartItem(item) != null) continue;
				mergeCnt++;
			}
		}

		// 쿠키 카트 정보 초기화 
		setCookieCart(response, new CartCookieVO());
		
		return mergeCnt;
	}
	

	/**
	 * 쿠키 카트(비로그인 상태의 카트정보)에 존재하는 자료 개수를 리턴한다. 
	 * 
	 * @param request
	 * @param response
	 * @param cartTypeCd
	 * @return
	 * @throws Exception
	 */
	public int countCartItemsFromCookie(HttpServletRequest request, HttpServletResponse response, String cartTypeCd) throws Exception {
		
		if(StringUtil.isEmpty(cartTypeCd)) return 0;
		
		String targetCookieName = CART_COOKIE_NAME + cartTypeCd;
		
		String cartStr = getCookie(request, targetCookieName);
		if(StringUtil.isEmpty(cartStr)) return 0;

		String[] cartItemsStr = cartStr.split(":");
		int retCnt = 0;
		for(String itemStr : cartItemsStr) {
			if(StringUtil.isEmpty(itemStr)) continue; 
			retCnt++;
		}
		
		return retCnt;
	}
	
	
	/**
	 * 사용자 카트의 자료 개수를 리턴한다.  
	 *  
	 * @param mbInfoId
	 * @param cartTypeCd
	 * @return
	 * @throws Exception
	 */
	public int countCartItems(String mbInfoId, String cartTypeCd) throws Exception {
		return cartDAO.countCartItems(mbInfoId, cartTypeCd);
	}
	
}
