package com.softwarebr.nunu.service.train.impl;

import com.alibaba.fastjson.JSONObject;
import com.brframework.common.utils.DateTimeUtils;
import com.brframework.commondb.core.ControllerPageHandle;
import com.brframework.commonweb.exception.HandleException;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.softwarebr.nunu.domain.ActivityLogExcel;
import com.softwarebr.nunu.domain.VisualizationDate;
import com.softwarebr.nunu.entity.train.Activity;
import com.softwarebr.nunu.entity.train.ActivityLog;
import com.softwarebr.nunu.dao.train.ActivityLogDao;
import com.softwarebr.nunu.json.admin.visual.VisualActivityResult;
import com.softwarebr.nunu.json.api.train.ActivityLogResult;
import com.softwarebr.nunu.service.oper.AreaService;
import com.softwarebr.nunu.service.train.ActivityLogService;
import com.brframework.commondb.core.AbstractEntityService;
import com.brframework.commondb.core.CommonRepository;
import com.softwarebr.nunu.service.train.ActivityService;
import com.softwarebr.nunu.util.AmountConversionUtil;
import com.softwarebr.nunu.util.ExcelUtils;
import com.softwarebr.nunu.util.UUIDGenerator;
import com.softwarebr.nunu.util.WordUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author lilin
 * @date 2020/03/11 15:30:46
 */

@Slf4j
@Service
public class ActivityLogServiceImpl extends AbstractEntityService<ActivityLog, Long, Object> implements ActivityLogService {

    @Autowired
    private ActivityLogDao activityLogDao;

    @Autowired
    private ActivityService activityService;

    @Autowired
    private AreaService areaService;

    @Override
    public CommonRepository<Long, ActivityLog> getRepository() {
        return activityLogDao;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ActivityLogResult activityLogSave(ActivityLog log) {
        ActivityLogResult activityLogResult = new ActivityLogResult();
        Activity activity = activityService.accessObject(log.getActivityId());
        if(activity.getSignStartDate().compareTo(LocalDateTime.now())>0){
            throw new HandleException("活动报名时间未开始，报名失败");
        }
        if (activity.getSignEndDate().compareTo(LocalDateTime.now()) <= 0) {
            throw new HandleException("活动报名时间已截止，报名失败");
        }
        if (activity.getEnrolment() >= activity.getCapacity()) {
            throw new HandleException("活动已爆满，报名失败");
        }
        if (activity.getPublisher().equals(log.getMemberId())) {
            throw new HandleException("系统检测活动发布者与活动报名用户相同，报名失败");
        }
        Integer enrolment = activity.getCapacity() - activity.getEnrolment();
        if(enrolment< log.getEnrolment()){
            throw new HandleException(String.format("报名人数已超出剩余报名人数，活动剩余报名人数%s人，报名失败", enrolment));
        }
        if (activity.getCategory().equals(Activity.CATEGORY_INNOVATE)) {
            log.setVoucherCode(UUIDGenerator.getSixDigitRandom());
            log.setFailureStatus(ActivityLog.FAILURE_STATUS_YES);
            activityService.activityEnrolment(log.getActivityId(), log.getEnrolment());
        } else {
            log.setOrderNo(UUIDGenerator.getOrderIdByUUId());
            log.setFailureStatus(ActivityLog.FAILURE_STATUS_NO);
        }
        log.setCreateDate(LocalDateTime.now());
        log = save(log);
        activityLogResult.setId(log.getId());
        activityLogResult.setStartDate(activity.getStartDate());
        activityLogResult.setAddress(areaService.addressSplicing(activity.getProvinceId(), activity.getCityId(), activity.getAreaId()));
        activityLogResult.setVoucherCode(log.getVoucherCode());
        activityLogResult.setFailureStatus(log.getFailureStatus());
        activityLogResult.setOrderNo(log.getOrderNo());
        return activityLogResult;
    }

    @Override
    public ActivityLogResult activityVoucherCode(String orderNo) {
        ActivityLog activityLog = activityLogDao.findByOrderNo(orderNo);
        ActivityLogResult activityLogResult = new ActivityLogResult();
        Activity activity = activityService.accessObject(activityLog.getActivityId());
        activityLogResult.setStartDate(activity.getStartDate());
        activityLogResult.setAddress(areaService.addressSplicing(activity.getProvinceId(), activity.getCityId(), activity.getAreaId()));
        activityLogResult.setVoucherCode(activityLog.getVoucherCode());
        activityLogResult.setId(activityLog.getId());
        activityLogResult.setFailureStatus(activityLog.getFailureStatus());
        return activityLogResult;
    }

    @Override
    public void activityReceiptDownload(HttpServletResponse response, Long id) throws IOException {
        ActivityLog activityLog = accessObject(id);
        Activity activity = activityService.accessObject(activityLog.getActivityId());
        BigDecimal price = AmountConversionUtil.out(activity.getPrice());
        Map<String, String> map = Maps.newHashMap();
        map.put("activityName", activity.getName());
        map.put("startDate", activity.getStartDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
        map.put("endDate", activity.getEndDate().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")));
        map.put("address", areaService.addressSplicing(activity.getProvinceId(), activity.getCityId(), activity.getAreaId()));
        map.put("price", price.longValue() > 0 ? price.toString() : "0.00");
        map.put("coverUri", WordUtils.imageBase64(activity.getCoverUri()));
        map.put("name", activityLog.getName());
        map.put("contact", activityLog.getContact());
        map.put("companyName", activityLog.getCompanyName());
        map.put("position", activityLog.getPosition());
        map.put("voucherCode", activityLog.getVoucherCode());
        map.put("enrolment", activityLog.getEnrolment().toString());
        WordUtils.exportMillCertificateWord(response, map);
    }


    @Override
    public void activityExcelDownload(HttpServletResponse response, Long activityId) {
        String dateTime = DateFormatUtils.format(new Date(), "yyyyMMddhhmm");
        Activity activity = activityService.accessObject(activityId);
        List<ActivityLogExcel> logExcel = ControllerPageHandle.convertListTo(activityLogDao.findByActivityIdAndFailureStatus(activityId, ActivityLog.FAILURE_STATUS_YES), ActivityLogExcel.class);
        try {
            //清空缓存
            response.reset();
            String fileName = activity.getName().concat(dateTime).concat(".xls");
            //开始到处excel文件
            //1.设置文件ContentType类型，这样设置，会自动判断下载文件类型
            response.setHeader("Content-Disposition", "attachment;filename=".concat(String.valueOf(URLEncoder.encode(fileName, "UTF-8"))));
            //定义下载的类型，标明是excel文件
            response.setContentType("application/vnd.ms-excel");
            OutputStream output = response.getOutputStream();
            Map<String, String> headers = Maps.newLinkedHashMap();
            headers.put("id", "序号");
            headers.put("name", "姓名");
            headers.put("voucherCode", "入场码");
            headers.put("contact", "联系方式");
            headers.put("companyName", "公司名称");
            headers.put("position", "职位");
            headers.put("enrolment", "报名人数");
            headers.put("createDate", "报名时间");
            ExcelUtils.exportExcel(JSONObject.toJSONString(logExcel), headers, output);
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void voucherCodeUpdate(String orderNo) {
        activityLogDao.updateVoucherCode(orderNo, UUIDGenerator.getSixDigitRandom(), ActivityLog.FAILURE_STATUS_YES);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void failureStatusUpdate(String orderNo) {
        activityLogDao.updateFailureStatus(orderNo, ActivityLog.FAILURE_STATUS_NO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void enrolmentUpdate(String orderNo, Integer enrolment){
        activityLogDao.updateEnrolment(orderNo, enrolment);
    }

    @Override
    public List<VisualActivityResult> getActivityApplyTotal(String minDateTime, String maxDateTime) {
        LocalDateTime maxDate = LocalDateTime.now().plusYears(100);
        LocalDateTime minDate = LocalDateTime.now().minusYears(100);
        List<VisualActivityResult> activityResults = Lists.newArrayList();
        if (null != minDateTime) {
            minDate = LocalDateTime.parse(minDateTime, DateTimeUtils.FORMATTER_DEFAULT_YMDHMS);
        }
        if (null != maxDateTime) {
            maxDate = LocalDateTime.parse(maxDateTime, DateTimeUtils.FORMATTER_DEFAULT_YMDHMS);
        }
        int j = 0;
        for (int i = 1; i <= 10; i++) {
            VisualActivityResult activityResult = new VisualActivityResult();
            if (i <= 7) {
                activityResult.setEnrolmentTotal(activityLogDao.countActivityLogByType(i, Activity.CATEGORY_INNOVATE, minDate, maxDate));
                activityResult.setTypeTitle(activityService.activityType(Activity.CATEGORY_INNOVATE).get(i));
                activityResult.setType(i);
            } else {
                j++;
                activityResult.setEnrolmentTotal(activityLogDao.countActivityLogByType(j, Activity.CATEGORY_TRAIN, minDate, maxDate));
                activityResult.setTypeTitle(activityService.activityType(Activity.CATEGORY_TRAIN).get(j));
                activityResult.setType(i);
            }
            activityResults.add(activityResult);
        }
        return activityResults;
    }

}