package com.neusoft.smart.pos.trade.service;


import com.neusoft.smart.pos.constants.DictionaryConstant;
import com.neusoft.smart.pos.dto.trade.request.GetBillDetailsRequest;
import com.neusoft.smart.pos.dto.trade.response.*;
import com.neusoft.smart.pos.dto.trade.response.GetAcceptBillsResponse.BillMonthDetail;
import com.neusoft.smart.pos.dto.trade.response.GetBillDetailsResponse.BillSubjectDetail;
import com.neusoft.smart.pos.dto.trade.response.GetBillResponse.BillPayType;
import com.neusoft.smart.pos.dto.trade.response.GetBillResponse.BillSubject;
import com.neusoft.smart.pos.dto.trade.response.GetNoAcceptBillNumbersResponse.BillNumber;
import com.neusoft.smart.pos.framework.bean.PaginationExtendBean;
import com.neusoft.smart.pos.framework.exception.BusinessCommonException;
import com.neusoft.smart.pos.framework.utils.DateUtils;
import com.neusoft.smart.pos.framework.utils.ListUtils;
import com.neusoft.smart.pos.order.constants.TradeErrorCode;
import com.neusoft.smart.pos.payorder.persistent.domain.PayTypeDict;
import com.neusoft.smart.pos.payorder.repository.PayChannelRepository;
import com.neusoft.smart.pos.trade.persistent.domain.*;
import com.neusoft.smart.pos.trade.persistent.ext.domain.BillCycleExt;
import com.neusoft.smart.pos.trade.repository.*;
import com.neusoft.smart.pos.trade.utils.BillTaskUtils;
import lombok.val;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service("billService")
public class BillService {

	private final static Logger logger = LoggerFactory.getLogger(BillService.class);
	
	@Autowired
	private BillSettlementCycleRepository billSettlementCycleRepository;
	
	@Autowired
	private BillTaskScheduleService billTaskScheduleService;
	
	@Autowired
	private BillDetailRepository billDetailRepository;
	
	@Autowired
	private BillMasterRepository billMasterRepository;
	
	@Autowired
	private PayChannelRepository payChannelRepository;
	
	@Autowired
	private PayTypeRepository payTypeRepository;
	
	@Autowired
	private BillShopRepository billShopRepository;
	
	@Autowired
	private BillDetailProfitRepository billDetailProfitRepository;
	
	@Autowired
	private BillSettlementTaskRepository billSettlementTaskRepository;
	
	private List<String> tradeMchPayChannelList;
	private List<PayTypeDict> tradePayTypeDicts;
	
	/**
	 * 商户归档账单信息查询方法
	 * @return
	 */
	public GetAcceptBillsResponse queryAcceptBills(Integer orgId, List<Integer> shopIds, String startTime, String endTime) {
		if(StringUtils.isEmpty(startTime)||StringUtils.isEmpty(endTime)){
			throw new BusinessCommonException(TradeErrorCode.BILL_QUERY_TIME_NOT_EMPTY);
		}
		
		//1.根据时间范围查询归档账单编号列表
        //2.查询该集团周期规则
        BillSettlementCycle billSettlementCycle = billSettlementCycleRepository.queryBillSettlementCycleByOrgId(orgId);
		List<String> monthList = getMonthList(startTime,endTime,billSettlementCycle,true);
		List<BillMonthDetail> billMonthList = new ArrayList<>();
		BillMonthDetail billMonthDetail;
		
		queryPayInfo(orgId);
		
		//2.查询归档结算单信息
		for(int j=0;j<monthList.size();j++){
			billMonthDetail = new BillMonthDetail();
			List<GetBillResponse> billList = new ArrayList<>();
			
			//2.1 遍历账单列表查询账单信息
			for(int i=0;i<shopIds.size();i++){
				//2.2 查询该门店该月份的账单编号列表
				List<Map> billNumberList = billDetailRepository.queryBillNumberList(orgId,shopIds.get(i),monthList.get(j));
				for(int z=0;z<billNumberList.size();z++) {
					GetBillResponse bill = queryBillsByBillNumber(orgId, shopIds.get(i), billNumberList.get(z).get("billNumber").toString(), DictionaryConstant.BILL_ACCEPT_STATUS_YES.getCode());
					//2.3 判断是否可做归档操作
					if (null != bill) {
						bill.setAcceptFlag("0");    //是否可归档@0:不可归档@1:可归档
						billList.add(bill);
					}
				}
			}
			
			//2.2 整理返回数据
			billMonthDetail.setMonth(monthList.get(j));
			billMonthDetail.setMonthName(monthList.get(j));
			billMonthDetail.setBillList(billList);
			billMonthList.add(billMonthDetail);
		}
		
		//4.整理返回数据信息
		GetAcceptBillsResponse acceptBillsResponse = new GetAcceptBillsResponse();
		acceptBillsResponse.setBillMonthList(billMonthList);
		return acceptBillsResponse;
	}
	
	/**
	 * 商户未结算账单信息查询方法
	 * @return
	 */
	public GetNoAcceptBillsResponse queryNoAcceptBills(Integer orgId, List<Integer> shopIds,String billNumber,String rebuild) {
		//1.查询该账单生成状态
		BillSettlementTask billSettlementTask = billSettlementTaskRepository.queryBillSettlementTask(orgId,billNumber);
		if(null == billSettlementTask){
			GetNoAcceptBillsResponse noAcceptBillsResponse = new GetNoAcceptBillsResponse();
			noAcceptBillsResponse.setTaskStatus(executeTask(orgId,shopIds,billNumber).getTaskStatus());
			return noAcceptBillsResponse;
		}else{
			//表示已存在该结算单生成任务
			if(billSettlementTask.getTaskStatus().equals(DictionaryConstant.BILL_TASK_STATUS_1.getCode())){
				GetNoAcceptBillsResponse noAcceptBillsResponse = new GetNoAcceptBillsResponse();
				noAcceptBillsResponse.setTaskStatus(executeTask(orgId,shopIds,billNumber).getTaskStatus());
				return noAcceptBillsResponse;
			}else if(rebuild.equals("1")&&!billSettlementTask.getTaskStatus().equals(DictionaryConstant.BILL_TASK_STATUS_1.getCode())){
				//1.查询该账单是否已经生成，如果已经生成则直接返回
				BillMaster billMaster = billMasterRepository.queryBillMasterByBillNumber(orgId,billNumber);
				if(null != billMaster){
					if(billMaster.getAcceptStatus().equals(DictionaryConstant.BILL_ACCEPT_STATUS_YES.getCode())){
						throw new BusinessCommonException(TradeErrorCode.BILL_IS_ACCEPT);
					}
				}
				
				//强制账单重新生成
				billMasterRepository.deleteBillMasterByBillNumber(orgId,billNumber);
				billDetailRepository.deleteBillDetailByBillNumber(orgId,billNumber);
				billDetailProfitRepository.deleteBillDetailProfitByBillNumber(orgId,billNumber);
				billSettlementTaskRepository.deleteBillSettlementTask(orgId,billNumber);
				
				GetNoAcceptBillsResponse noAcceptBillsResponse = new GetNoAcceptBillsResponse();
				noAcceptBillsResponse.setTaskStatus(executeTask(orgId,shopIds,billNumber).getTaskStatus());
				return noAcceptBillsResponse;
			}
		}
		
		//3.查询未归档结算单信息
        List<GetBillResponse> billResponseList = new ArrayList<>();
		queryPayInfo(orgId);
        for(int i=0;i<shopIds.size();i++){
            GetBillResponse billResponse = queryBillsByBillNumber(orgId,shopIds.get(i),billNumber,DictionaryConstant.BILL_ACCEPT_STATUS_NO.getCode());
            //3.1 判断是否可做归档操作，如果账单结算时间小于等于当前时间则不能进行归档操作
	        if(null != billResponse) {
		        if (billResponse.getCycleEndTime() > (new Date()).getTime()) {
			        billResponse.setAcceptFlag("0");    //是否可归档@0:不可归档@1:可归档
		        } else {
			        billResponse.setAcceptFlag("1");
		        }
		        billResponseList.add(billResponse);
	        }
        }
        
		//4.整理返回数据信息
        GetNoAcceptBillsResponse noAcceptBillsResponse = new GetNoAcceptBillsResponse();
		noAcceptBillsResponse.setBillList(billResponseList);
		noAcceptBillsResponse.setTaskStatus(billSettlementTask.getTaskStatus());
		return noAcceptBillsResponse;
	}
	
	private BillSettlementTask executeTask(Integer orgId,List<Integer> shopIds,String billNumber){
		BillSettlementTask billSettlementTask = billTaskScheduleService.executeGenerateBillTask(orgId,shopIds,billNumber);
		GetNoAcceptBillsResponse noAcceptBillsResponse = new GetNoAcceptBillsResponse();
		noAcceptBillsResponse.setTaskStatus(billSettlementTask.getTaskStatus());
		return billSettlementTask;
	}
	
    /**
     * 根据门店ID和账单编号查询账单列表
     * @param orgId
     * @param shopId
     * @param billNumber
     */
	public GetBillResponse queryBillsByBillNumber(Integer orgId, Integer shopId, String billNumber,String acceptStatus){
        GetBillResponse billResponse = null;
        BillMaster billMaster = billMasterRepository.queryBillMasterByBillNumber(orgId,shopId,billNumber,acceptStatus);
        if(null != billMaster){
	        billResponse = new GetBillResponse();
	        BeanUtils.copyProperties(billMaster,billResponse);
	
	        //查询账单总笔数
	        billResponse.setPayCount(billDetailRepository.queryBillDetailCount(shopId,billNumber));
	        
	        //查询主体分润对象列表
	        List<BillSubject> billSubjectList = queryBillSubjectListByBillNumber(orgId,shopId,billNumber);
	        billResponse.setBillSubjectList(billSubjectList);
        }
        return billResponse;
    }
	
	/**
	 * 查询支付相关参数信息
	 * @param orgId
	 */
	private void queryPayInfo(Integer orgId){
	    tradeMchPayChannelList = payChannelRepository.queryOrgPayTypeList(orgId);
	    tradePayTypeDicts = payTypeRepository.queryPayTypes(null,null);
    }
	
	/**
	 * 查询门店分润主体分润信息
	 * @return
	 */
	public List<BillSubject> queryBillSubjectListByBillNumber(Integer orgId, Integer shopId, String billNumber){
		List<BillSubject> billSubjectList = new ArrayList<>();
		
		//1.从规则表中查询该集团下所有门店的全部分润主体集合
		List<Map<String,String>> subjectNameList = billDetailRepository.querySubjectNameListByOrgId(orgId);
		
		for(int i=0;i<subjectNameList.size();i++){
			BillSubject billSubject = new BillSubject();
			billSubject.setSubjectName(subjectNameList.get(i).get("subjectName"));  //获取主体名称
			billPayTypesByBillNumberHandle(orgId,shopId,billNumber,billSubject);
			billSubjectList.add(billSubject);
		}
		
		return billSubjectList;
	}
 
	/**
	 * 查询门店支付渠道分润信息(暂不考虑门店有单独支付渠道)
	 * @return
	 */
	public void billPayTypesByBillNumberHandle(Integer orgId, Integer shopId, String billNumber,BillSubject billSubject){
		List<BillPayType> billPayTypeList = new ArrayList<>();
		Integer payCount = 0;
		BigDecimal profitAmount = BigDecimal.ZERO;
		//1.查询该集团已开通支付渠道列表信息
		for(int i=0;i<tradeMchPayChannelList.size();i++){
			BillPayType billPayType = new BillPayType();
			billPayType.setPayType(tradeMchPayChannelList.get(i));
			//存入支付方式名称
			tradePayTypeDicts.forEach(tradePayType->{
				if(billPayType.getPayType().equals(tradePayType.getPayType())){
					billPayType.setPayTypeName(tradePayType.getName());
					return;
				}
			});
			//查询门店支付方式信息
			Map shopPayTypeProfitMap = billDetailRepository.queryShopPayTypeProfit(shopId,billNumber,billPayType.getPayType(),billSubject.getSubjectName());
			billPayType.setProfitAmount(new BigDecimal(String.valueOf(shopPayTypeProfitMap.get("billAmount"))));
			billPayType.setPayCount(Integer.parseInt(shopPayTypeProfitMap.get("payCount").toString()));
			//查询主体分润信息
			payCount = payCount + billPayType.getPayCount();
			profitAmount = profitAmount.add(new BigDecimal(billPayType.getProfitAmount()));
			billPayTypeList.add(billPayType);
		}
		billSubject.setProfitAmount(profitAmount);
		billSubject.setPayCount(payCount);
		billSubject.setBillPayTypeList(billPayTypeList);
	}
	
	/**
	 * 商户结算账单是否存在信息查询方法
	 * @return
	 */
	public GetBillExistStatusResponse queryBillExistStatus(Integer orgId,Integer shopId,String billNumber){
		Integer billCount;
		if(shopId == 0){
			billCount = billMasterRepository.queryBillMasterCountByBillNumber(orgId,billNumber);
		}else{
			billCount = billMasterRepository.queryBillMasterCountByBillNumber(orgId,shopId,billNumber);
		}
		return new GetBillExistStatusResponse(billCount);
	}
	
	/**
	 * 商户结算账单归档状态更新方法
	 * @return
	 */
	public PutBillAcceptResponse updateBillAcceptStatus(Integer orgId, Integer shopId, String billNumber){
		if(!queryBillExistStatus(orgId,shopId,billNumber).isExist()){
			throw new BusinessCommonException(TradeErrorCode.BILL_NOT_EXIST);
		}
		
		Boolean bool;
		if(shopId == 0){
			bool = billMasterRepository.updateOrderStatusByOrderNumber(orgId,billNumber,DictionaryConstant.BILL_ACCEPT_STATUS_YES.getCode());
		}else{
			bool = billMasterRepository.updateOrderStatusByOrderNumber(orgId,shopId,billNumber,DictionaryConstant.BILL_ACCEPT_STATUS_YES.getCode());
		}
		return new PutBillAcceptResponse(bool);
	}
	
	/**
	 * 月份列表获取方法
	 * @param startMonth
	 * @param endMonth
	 * @return
	 */
	private List<String> getMonthList(String startMonth,String endMonth,BillSettlementCycle billSettlementCycle,Boolean isQuery){
		List<String> monthList = new ArrayList<>();
		Date startDate = DateUtils.parse(startMonth,DateUtils.FORMAT_SHORTER);//定义起始日期
		Date endDate = DateUtils.parse(endMonth,DateUtils.FORMAT_SHORTER);//定义结束日期  可以去当前月也可以手动写日期。
		Integer monthCount = DateUtils.countMonths(startDate,endDate);
		
		if(billSettlementCycle == null){
			throw new BusinessCommonException(TradeErrorCode.BILL_SETTLEMENT_CYCLE_NOT_EXIST);
		}
		
		//1.处理首月结算时间(目前只做简化处理)，如果创建时间小于结算日，则向前推一个月
        Boolean removeLast = false; //判断是否需要删除最后一条结算时间
        if(!isQuery&&billSettlementCycle.getBillDayType().equals("1")){
            Integer createDay = startDate.getDay();
            Integer settlementDay = billSettlementCycle.getBillDay();
            if(createDay < settlementDay){
                monthList.add(DateUtils.format(DateUtils.subMonth(startDate,1),DateUtils.FORMAT_SHORTER_EXT));
            }
            
            Integer currentDay = DateUtils.getCurrentDay();//当前日
            if(currentDay < settlementDay){
                removeLast = true;
            }
        }
		
		for(int i=0;i<=monthCount;i++){
			monthList.add(DateUtils.format(DateUtils.addMonth(startDate,i),DateUtils.FORMAT_SHORTER_EXT));
		}
		
		if(!isQuery&&removeLast){
            monthList.remove(monthList.size()-1);
        }
		return monthList;
	}
    
    /**
     * 商户未结算账单信息查询方法
     * @return
     */
    public GetBillDetailsResponse queryBillDetails(GetBillDetailsRequest billDetailsRequest){
		//1.校验参数信息
    	
	    //2.整理查询条件
	    val example = queryBillDetailsExampleHandle(billDetailsRequest);
    	
	    //3.查询账单详情信息
	    val billDetailCount = billDetailRepository.queryBillDetailCount(example);    //查询满足条件的总记录条数
	    if (billDetailsRequest.getIsPage()) {
		    example.setLimit(billDetailsRequest.getLimit());
		    example.setOffset(billDetailsRequest.getOffset());
	    }
	    List<BillDetail> billDetailList = billDetailRepository.queryBillDetails(example);
	
	    //4.进行数据整理
	    val billDetailDataList = ListUtils.convertListToList(billDetailList, GetBillDetailsResponse.BillDetailsData.class);
	    val paginationExtendBean = new PaginationExtendBean<GetBillDetailsResponse.BillDetailsData>();
	
	    //5.查询系统支付渠道信息
	    val tradePayTypeDicts = payTypeRepository.queryPayTypes(null, null);
	    if (null != billDetailDataList && billDetailDataList.size() > 0) {
        
            List<Map<String,String>> subjectNameList = billDetailRepository.querySubjectNameListByOrgId(billDetailsRequest.getOrgId());
	        
		    billDetailDataList.forEach(billDetailData -> {
			    //5.1处理支付方式名称
			    if (!StringUtils.isEmpty(billDetailData.getPayType())) {
				    tradePayTypeDicts.forEach(tradePayTypeDict -> {
					    if (billDetailData.getPayType().equals(tradePayTypeDict.getPayType())) {
						    billDetailData.setPayTypeName(tradePayTypeDict.getName());
						    return;
					    }
				    });
			    }
			    //5.2处理订单类型名称
			    billDetailData.setOrderTypeName(getOrderTypeName(billDetailData.getOrderType()));
       
			    //5.3存储分润主体列表
                List<BillDetailProfit> billDetailProfitList = billDetailProfitRepository.queryBillDetailProfitByOrderNumber(billDetailData.getOrgId(),billDetailData.getShopId(),billDetailData.getOrderNumber(),billDetailData.getBillNumber());
                List<BillSubjectDetail> billSubjectDetailList = new ArrayList<>();
                for(int i=0;i<subjectNameList.size();i++){
                    BillSubjectDetail billSubjectDetail = new BillSubjectDetail();
                    billSubjectDetail.setSubjectName(subjectNameList.get(i).get("subjectName"));  //获取主体名称
                    for(int j=0;j<billDetailProfitList.size();j++){
                        if(billSubjectDetail.getSubjectName().equals(billDetailProfitList.get(j).getSubjectName())){
                            billSubjectDetail.setProfitAmount(billDetailProfitList.get(j).getProfitAmount());
                            billSubjectDetail.setProfitRate(billDetailProfitList.get(j).getProfitRate());
                            break;
                        }
                    }
                    billSubjectDetailList.add(billSubjectDetail);
                }
                billDetailData.setBillSubjectDetailList(billSubjectDetailList);
			
		    });
	    }
	    paginationExtendBean.setRows(billDetailDataList);
	    paginationExtendBean.setTotal(billDetailCount);
	    
        //2.整理返回明细数据
        GetBillDetailsResponse billDetailsResponse = new GetBillDetailsResponse();
	    billDetailsResponse.setPaginationExtendBean(paginationExtendBean);
        return billDetailsResponse;
    }
	
	/**
	 * 整理查询条件信息
	 */
	private BillDetailExample queryBillDetailsExampleHandle(GetBillDetailsRequest billDetailsRequest) {
		val example = new BillDetailExample();
		example.createCriteria()
				.andOrgIdEqualTo(billDetailsRequest.getOrgId())
				.andShopIdEqualTo(billDetailsRequest.getShopId())
				.andBillNumberEqualTo(billDetailsRequest.getBillNumber())
		;
		example.setOrderByClause("created_at desc");
		return example;
	}
	
	/**
	 * 根据订单状态获取订单状态名称
	 * @param orderType
	 * @return
	 */
	private String getOrderTypeName(String orderType) {
		String orderTypeName = "";
		if (!StringUtils.isEmpty(orderType)) {
			DictionaryConstant dict = DictionaryConstant.getEnumByCode(DictionaryConstant.ORDER_TYPE.getCode(), orderType);
			orderTypeName = dict.getValue();
		}
		return orderTypeName;
	}
	
	/**
	 * 未结算周期列表查询方法
	 * @param orgId
	 * @return
	 */
	public GetNoAcceptBillNumbersResponse queryNoAcceptBillNumbers(Integer orgId){
		//1.获取门店创建时间
		BillShop billShop = billShopRepository.queryBillShopByOrgId(orgId);
		String startTime = DateUtils.format(billShop.getCreatedAt(),DateUtils.FORMAT_SHORTER);
		String endTime = DateUtils.format(new Date(),DateUtils.FORMAT_SHORTER);
        
        //2.查询该集团周期规则
        BillSettlementCycle billSettlementCycle = billSettlementCycleRepository.queryBillSettlementCycleByOrgId(orgId);
		
		List<String> monthList = getMonthList(startTime,endTime,billSettlementCycle,false);
		List<BillNumber> billNumberList = new ArrayList<>();
		
		for(int i=0;i<monthList.size();i++){
			BillCycleExt billCycleExt = BillTaskUtils.getBillCycleByBillMonth(orgId,monthList.get(i),billSettlementCycle);
			if(null != billCycleExt){
                //查询账单数据是否已经存在
                Integer billCount = billMasterRepository.queryBillMasteAcceptrCountByBillNumber(orgId,billCycleExt.getBillNumber());
                if(billCount == 0){
                    BillNumber billNumber = new BillNumber();
                    BeanUtils.copyProperties(billCycleExt,billNumber);
                    billNumberList.add(billNumber);
                }
            }
		}
		
		GetNoAcceptBillNumbersResponse noAcceptBillNumbersResponse = new GetNoAcceptBillNumbersResponse();
		noAcceptBillNumbersResponse.setBillCycleList(billNumberList);
		return noAcceptBillNumbersResponse;
	}
}
