package com.ltgk.boat.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltgk.boat.domain.dto.DsOutPortDTO;
import com.ltgk.boat.domain.dto.GetOutPortReq;
import com.ltgk.boat.domain.dto.SetConfirmReq;
import com.ltgk.boat.domain.entity.DsBoatData;
import com.ltgk.boat.domain.entity.DsOutPort;
import com.ltgk.boat.domain.vo.DsOutPortVO;
import com.ltgk.boat.mapper.DsOutPortMapper;
import com.ltgk.boat.service.DsBoatDataService;
import com.ltgk.boat.service.IDsOutPortService;
import com.ltgk.common.constant.CacheConstants;
import com.ltgk.common.constant.SysConstant;
import com.ltgk.common.core.domain.entity.SysRole;
import com.ltgk.common.core.domain.entity.SysUser;
import com.ltgk.common.core.redis.RedisCache;
import com.ltgk.common.enums.EnterOutPortStatus;
import com.ltgk.common.enums.PersonalDataEnums;
import com.ltgk.common.utils.DateUtils;
import com.ltgk.common.utils.SecurityUtils;
import com.ltgk.common.utils.bean.BeanUtils;
import com.ltgk.common.utils.poi.ExcelUtil;
import com.ltgk.crew.domain.entity.DsBoatCrew;
import com.ltgk.crew.domain.entity.DsCrewOutCheck;
import com.ltgk.crew.service.IDsBoatCrewService;
import com.ltgk.crew.service.IDsCrewOutCheckService;
import com.ltgk.port.domain.entity.DsPort;
import com.ltgk.port.service.IDsPortService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.ltgk.common.utils.PageUtils.startPage;


/**
 * 渔船出港信息Service业务层处理
 *
 * @author Qi ChengBin
 * @date 2024-12-19
 */
@Service
public class DsOutPortServiceImpl extends ServiceImpl<DsOutPortMapper, DsOutPort> implements IDsOutPortService {

    @Resource
    private IDsBoatCrewService dsBoatCrewService;
    @Resource
    private IDsCrewOutCheckService dsCrewOutCheckService;
    @Resource
    private DsBoatDataService dsBoatDataService;
    @Resource
    private IDsPortService dsPortService;
    @Resource
    private RedisCache redisCache;

    /**
     * 分页查询渔船出港信息
     *
     * @param req:
     * @return java.util.List<com.ltgk.boat.domain.entity.DsOutPort>
     * @author Qi ChengBin
     * @date 2024/12/19 14:20
     */
    @Override
    public List<DsOutPort> selectByPage(GetOutPortReq req) {
        req.queryCheck();
        DsOutPort dsOutPort = new DsOutPort();
        BeanUtils.copyProperties(req, dsOutPort);
        LambdaQueryWrapper<DsOutPort> wrapper = new LambdaQueryWrapper<>(dsOutPort);

        String startTime = req.getStartTime();
        String endTime = req.getEndTime();
        boolean beNotBlankTime = StringUtils.isNotBlank(startTime) && StringUtils.isNotBlank(endTime);

        wrapper.between(beNotBlankTime, DsOutPort::getOutTime, startTime, endTime)
                .orderByDesc(DsOutPort::getOutTime);

        // 根据登录用户判断是否有查询自己数据的角色信息，只要有查询自己数据角色，就查询自己的数据
        List<SysRole> loginUserRoleList = SecurityUtils.getLoginUser().getUser().getRoles();

        if (loginUserRoleList.stream().anyMatch(item -> item.getRoleKey().equals(PersonalDataEnums.PERSONAL_DATA.getValue()))) {
            wrapper.eq(DsOutPort::getRegisterId, SecurityUtils.getUserId());
        }

        startPage(req.getPageNum(), req.getPageSize());
        List<DsOutPort> dsOutPortList = this.list(wrapper);
        // 获取船员信息
        if (!dsOutPortList.isEmpty()) {
            List<String> crewIdList = dsOutPortList.stream()
                    .filter(Objects::nonNull)
                    .map(DsOutPort::getCrewIds)
                    .filter(StringUtils::isNotBlank)
                    .flatMap(
                            crewIds -> {
                                if (StringUtils.isNotBlank(crewIds)) {
                                    return Arrays.stream(crewIds.split(","));
                                }
                                return Stream.empty();
                            }
                    )
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());
            if (!crewIdList.isEmpty()) {
                List<DsBoatCrew> dsBoatCrewList = dsBoatCrewService.listByIds(crewIdList);

                Map<String, DsBoatCrew> dsBoatCrewMap = dsBoatCrewList.stream()
                        .collect(Collectors.toMap(DsBoatCrew::getId, crew -> crew));

                dsOutPortList.forEach(item -> {
                    // 排除没有绑定船员的数据
                    if (StringUtils.isBlank(item.getCrewIds())) {
                        return;
                    }
                    List<String> crewIds = Arrays.stream(item.getCrewIds().split(","))
                            .filter(StringUtils::isNotBlank)
                            .collect(Collectors.toList());
                    List<DsBoatCrew> associatedCrewList = crewIds.stream()
                            .map(dsBoatCrewMap::get)
                            .filter(Objects::nonNull)
                            .collect(Collectors.toList());
                    item.setBoatCrewList(associatedCrewList);
                });
            }
        }
        return dsOutPortList;
    }

    /**
     * 移动端添加渔船出港报备信息
     *
     * @param dsOutPortDTO:
     * @return boolean
     * @author Qi ChengBin
     * @date 2024/12/19 14:41
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addByApp(DsOutPortDTO dsOutPortDTO) {

        SysUser user = SecurityUtils.getLoginUser().getUser();

        DsOutPort dsOutPort = new DsOutPort();
        BeanUtils.copyProperties(dsOutPortDTO, dsOutPort);
        // 渔港信息
        DsPort port = dsPortService.getById(dsOutPortDTO.getPortId());
        // 获取渔船信息
        DsBoatData boatById = dsBoatDataService.getBoatById(dsOutPortDTO.getBoatId(), dsOutPortDTO.getBoatName());
        dsOutPort
                .setPortName(port.getPortName())
                .setPortId(port.getId())
                .setBoatId(boatById.getBoatId())
                .setBoatName(boatById.getBoatName())
                .setBoatMaterial(boatById.getBoatMaterial())
                .setLength(boatById.getLength())
                .setMainPower(boatById.getMainPower())
                .setRegisterId(String.valueOf(user.getUserId()))
                .setRegisterName(user.getNickName())
                .setRegisterUnit(SecurityUtils.getDeptName())
                .setRegisterPhone(SecurityUtils.getLoginUser().getUser().getPhonenumber())
                .setIsLocal(boatById.getIsLocal())
                .setStatus(EnterOutPortStatus.UN_CONFIRM.getCode())
                .setCreateBy(user.getNickName())
                .setCreateAt(DateUtils.getNowDate())
                .setUpdateBy(user.getNickName())
                .setUpdateAt(DateUtils.getNowDate())
        ;

        if (this.saveOrUpdate(dsOutPort)) {
            String dsOutPortId = dsOutPort.getId();
            // 保存船员申请信息
            LambdaQueryWrapper<DsBoatCrew> dsBoatCrewLambdaQueryWrapper = new LambdaQueryWrapper<>();
            dsBoatCrewLambdaQueryWrapper.in(DsBoatCrew::getId, Arrays.asList(dsOutPortDTO.getCrewIds().split(",")));
            List<DsBoatCrew> dsBoatCrewList = dsBoatCrewService.list(dsBoatCrewLambdaQueryWrapper);
            List<DsCrewOutCheck> dsCrewOutCheckList = new ArrayList<>();
            dsBoatCrewList.forEach(dsBoatCrew -> {
                DsCrewOutCheck dsCrewOutCheck = new DsCrewOutCheck();
                dsCrewOutCheck.setOutPortId(dsOutPortId)
                        .setPortId(dsOutPort.getPortId())
                        .setPortName(dsOutPort.getPortName())
                        .setCrewId(dsBoatCrew.getId())
                        .setCrewName(dsBoatCrew.getCrewName())
                        .setIdCard(dsBoatCrew.getIdCardNo())
                        .setCrewId(dsBoatCrew.getId())
                        .setTel(dsBoatCrew.getPhone())
                        .setPosition(dsBoatCrew.getBoatDutyName())
                        .setAddress(dsBoatCrew.getAddress())
                        .setCertificateNumber(dsBoatCrew.getCertificateCode())
                        .setStatus(EnterOutPortStatus.UN_CONFIRM.getCode())
                        .setIdCardPic(dsBoatCrew.getIdCardPic())
                        .setOutTime(dsOutPortDTO.getOutTime())
                        .setRemark(dsBoatCrew.getRemarks())
                        .setCreateAt(DateUtils.getNowDate())
                        .setCreateBy(user.getNickName())
                        .setUpdateAt(DateUtils.getNowDate())
                        .setUpdateBy(user.getNickName());

                dsCrewOutCheckList.add(dsCrewOutCheck);
            });
            dsCrewOutCheckService.saveBatch(dsCrewOutCheckList);

            // 将渔船出港申请存储到 redis 中，以便在点位数据渔船进出港时判断是否申报；；；根据申报的 出港时间 + 24h - 当前时间 来作为redis key 的过期时间
            Date overdueTime = DateUtil.offset(dsOutPort.getOutTime(), DateField.HOUR, 24);
            int intervalTime = (int) DateUtil.between(new Date(), overdueTime, DateUnit.HOUR);
            redisCache.setCacheObject(CacheConstants.DS_OUT_PORT_KEY + dsOutPort.getBoatId(), dsOutPort, intervalTime, TimeUnit.HOURS);

            return true;
        }
        return false;
    }

    /**
     * 渔船出港报备确认
     *
     * @param setConfirmReq:
     * @return boolean
     * @author Qi ChengBin
     * @date 2024/12/19 15:42
     */
    @Override
    public boolean confirm(SetConfirmReq setConfirmReq) {
        DsOutPort dsOutPort = new DsOutPort();
        // 查询分析是否有未审核的船员
//        LambdaQueryWrapper<DsCrewOutCheck> dsCrewOutCheckLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        dsCrewOutCheckLambdaQueryWrapper.eq(DsCrewOutCheck::getOutPortId, setConfirmReq.getId())
//                .eq(DsCrewOutCheck::getStatus, SysConstant.CHECK_STATUS_UNCHECKED);
//        if (dsCrewOutCheckService.count(dsCrewOutCheckLambdaQueryWrapper) > 0) {
//            throw new RuntimeException("存在未审核船员，需先审核才能确认");
//        }

        String userName = SecurityUtils.getLoginUser().getUser().getNickName();

        // 将出港渔船报备信息绑定的船员信息进行审核
        dsCrewOutCheckService.lambdaUpdate()
                .eq(DsCrewOutCheck::getOutPortId, setConfirmReq.getId())
                // 将没有进行审核的船员进行审核，单独审核的船员除外
                .eq(DsCrewOutCheck::getStatus, SysConstant.CHECK_STATUS_UNCHECKED)
                // 根据渔船的整体审核状态进行更新渔船绑定船员的审核状态
                .set(DsCrewOutCheck::getStatus, setConfirmReq.getStatus())
                .set(DsCrewOutCheck::getUpdateBy, userName)
                .set(DsCrewOutCheck::getUpdateAt, DateUtils.getNowDate())
                .update();


        BeanUtils.copyBeanProp(dsOutPort, setConfirmReq);
        dsOutPort.setId(setConfirmReq.getId())
                .setStatus(setConfirmReq.getStatus())
                .setUpdateAt(DateUtils.getNowDate())
                .setUpdateBy(userName)
                .setReviewTime(DateUtils.getNowDate())
                .setReviewUserId(SecurityUtils.getUserId().toString())
                .setReviewUserName(userName)
                .setReviewDesc(setConfirmReq.getReviewDesc())
                .setActualOutTime(DateUtils.parseDate(setConfirmReq.getActualOutTime()));
        if (this.updateById(dsOutPort)) {
            /*
            * TODO：保存操作人信息
            String statusStr = "审核驳回！";
            if (status.equals(SysConstant.CHECK_STATUS_PASS)) {
                statusStr = "审核通过";
            }
            //保存操作人信息
            SysCheckOperateRecord scor = new SysCheckOperateRecord();
            SysCheckOperateRecord entity = scor.setOperator(user.getUserName()).setOperatorId(user.getUserId()).setOperatorTel(user.getPhone())
                    .setDelFlag(Constants.FLAG_FALSE).setOperateObject(dsOutPort.getBoatName() + "出港申请").setOperateTime(new Date()).setResults(statusStr);
            sysCheckOperateRecordService.save(entity);
            * */
            /*
            * TODO:推送审核消息
            dsOutPort.setRemark(statusStr);
            checkResultPush(dsOutPort);
            * */
            /*
            * TODO:添加消息到通知信息表
            DsNotice dsNotice = new DsNotice();
            dsNotice.setNoticeTittle("出港申请审批").setNoticeTime(new Date())
                    .setContent(dsOutPort.getBoatName() + "出港申请审批" + statusStr).setNoticeType("通知")
                    .setNoticeUser(dsOutPort.getOwnerPhone())  //通知用户暂定使用船东手机号
                    .setCreateAt(new Date()).setCreateBy(user.getUserName()).setDelFlag(Constants.FLAG_FALSE);
            infoNoticeService.save(dsNotice1);
            * */
            return true;
        }
        return false;
    }

    @Override
    public void export(HttpServletResponse response, GetOutPortReq getOutPortReq) {
        LambdaQueryWrapper<DsOutPort> lqw = new LambdaQueryWrapper<>();
        lqw.ge(StringUtils.isNotBlank(getOutPortReq.getStartTime()), DsOutPort::getOutTime, getOutPortReq.getStartTime())
                .le(StringUtils.isNotBlank(getOutPortReq.getEndTime()), DsOutPort::getOutTime, getOutPortReq.getEndTime())
                .like(StringUtils.isNotBlank(getOutPortReq.getBoatName()), DsOutPort::getBoatName, getOutPortReq.getBoatName())
                .eq(StringUtils.isNotBlank(getOutPortReq.getBoatId()), DsOutPort::getBoatId, getOutPortReq.getBoatId())
                .like(StringUtils.isNotBlank(getOutPortReq.getPortName()), DsOutPort::getPortName, getOutPortReq.getPortName())
                .eq(StringUtils.isNotBlank(getOutPortReq.getPortId()), DsOutPort::getPortId, getOutPortReq.getPortId())
                .eq(Objects.nonNull(getOutPortReq.getStatus()), DsOutPort::getStatus, getOutPortReq.getStatus())
                .eq(DsOutPort::getIsLocal, getOutPortReq.getIsLocal())
                .orderByDesc(DsOutPort::getOutTime);
        List<DsOutPort> dsEnterPortList = this.list(lqw);
        List<DsOutPortVO> dsoutPortVOList = dsEnterPortList.stream().map(item -> {
            DsOutPortVO dsoutPortVO = new DsOutPortVO();
            BeanUtils.copyBeanProp(dsoutPortVO, item);
            if (ObjectUtils.isNotEmpty(item.getOutTime())) {
                dsoutPortVO.setOutTime(DateUtils.dateTime(item.getOutTime()));
            }
            if (ObjectUtils.isNotEmpty(item.getReviewTime())) {
                dsoutPortVO.setReviewTime(DateUtils.dateTime(item.getReviewTime()));
            }
            dsoutPortVO.setStatus(EnterOutPortStatus.getByCode(item.getStatus()));
            return dsoutPortVO;
        }).collect(Collectors.toList());
        ExcelUtil<DsOutPortVO> util = new ExcelUtil<>(DsOutPortVO.class);
        util.exportExcel(response, dsoutPortVOList, "渔船出港信息数据");
    }

    /**
     * 外地渔船出港登记
     *
     * @param dsOutPortDTO：
     * @return boolean
     * @author Qi ChengBin
     * @date 2025/3/4
     */
    @Override
    public boolean doRegistrationNotLocalBoat(DsOutPortDTO dsOutPortDTO) {
        String userName = SecurityUtils.getLoginUser().getUser().getNickName();
        DsOutPort dsOutPort = new DsOutPort();
        BeanUtils.copyProperties(dsOutPortDTO, dsOutPort);
        dsOutPort.setCreateBy(userName)
                .setCreateAt(DateUtils.getNowDate())
                .setUpdateBy(userName)
                .setUpdateAt(DateUtils.getNowDate());
        boolean flag = this.saveOrUpdate(dsOutPort);
        if (flag) {
            List<DsCrewOutCheck> dsCrewOutCheckList = dsOutPortDTO.getCrewOutCheckList();
            dsCrewOutCheckList.forEach(item -> item.setOutPortId(dsOutPort.getId()));
            flag = dsCrewOutCheckService.saveOrUpdateBatch(dsCrewOutCheckList);
        }
        return flag;
    }
}
