package com.ltgk.boat.service.impl;

import cn.hutool.core.util.IdcardUtil;
import cn.hutool.extra.pinyin.PinyinUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ltgk.boat.domain.dto.DsBoatBindCrewDTO;
import com.ltgk.boat.domain.entity.DsBoatBindCrew;
import com.ltgk.boat.domain.entity.DsBoatData;
import com.ltgk.boat.mapper.DsBoatBindCrewMapper;
import com.ltgk.boat.service.DsBoatDataService;
import com.ltgk.boat.service.IDsBoatBindCrewService;
import com.ltgk.common.constant.Constants;
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.utils.SecurityUtils;
import com.ltgk.common.utils.bean.BeanUtils;
import com.ltgk.crew.domain.entity.DsBoatCrew;
import com.ltgk.crew.service.IDsBoatCrewService;
import com.ltgk.system.service.ISysRoleService;
import com.ltgk.system.service.ISysUserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

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


/**
 * 渔船绑定船员Service业务层处理
 *
 * @author Qi ChengBin
 * @date 2024-12-18
 */
@Service
public class DsBoatBindCrewServiceImpl extends ServiceImpl<DsBoatBindCrewMapper, DsBoatBindCrew> implements IDsBoatBindCrewService {

    @Resource
    private DsBoatDataService dsBoatDataService;
    @Resource
    private IDsBoatCrewService dsBoatCrewService;
    @Resource
    private ISysRoleService sysRoleService;
    @Resource
    private ISysUserService sysUserService;

    /**
     * 分页查询船员绑定渔船数据
     *
     * @param dsBoatBindCrewDTO: 渔船绑定船员数据传输对象
     * @return java.util.List<com.ltgk.boat.domain.entity.DsBoatBindCrew>
     * @author Qi ChengBin
     * @date 2024/12/18 13:53
     */
    @Override
    public List<DsBoatBindCrew> findDsBoatBindCrewPage(DsBoatBindCrewDTO dsBoatBindCrewDTO) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String boatName = dsBoatBindCrewDTO.getBoatName();
        Integer pageNum = dsBoatBindCrewDTO.getPageNum();
        Integer pageSize = dsBoatBindCrewDTO.getPageSize();

        DsBoatBindCrew dsBoatBindCrew = new DsBoatBindCrew();
        BeanUtils.copyProperties(dsBoatBindCrewDTO, dsBoatBindCrew);

        LambdaQueryWrapper<DsBoatBindCrew> wrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isNotBlank(boatName)) {
            wrapper.eq(DsBoatBindCrew::getBoatName1, boatName)
                    .or()
                    .eq(DsBoatBindCrew::getBoatName2, boatName);
        } else {
            // 查询被绑定渔船
            LambdaQueryWrapper<DsBoatData> dsBoatDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
            dsBoatDataLambdaQueryWrapper.eq(DsBoatData::getHolderPhone, user.getPhonenumber())
                    .or()
                    .eq(DsBoatData::getHolderPhone, user.getPhonenumber());
            List<DsBoatData> dsBoatDataList = dsBoatDataService.list(dsBoatDataLambdaQueryWrapper);

            List<String> dsBoatNameList = dsBoatDataList.stream().map(DsBoatData::getBoatName).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(dsBoatNameList)) {
                wrapper.in(DsBoatBindCrew::getBoatName1, dsBoatNameList)
                        .or()
                        .in(DsBoatBindCrew::getBoatName2, dsBoatNameList);
            }
        }
        // 船东
        List<String> userRolesList = user.getRoles().stream().map(SysRole::getRoleKey).collect(Collectors.toList());
        if (userRolesList.contains(SysConstant.OPERATOR) || userRolesList.contains(SysConstant.SUPER_ADMIN)) {
            wrapper.eq(DsBoatBindCrew::getOwnerPhone, user.getPhonenumber());
        }
        startPage(pageNum, pageSize);
        return this.list(wrapper);
    }

    /**
     * 根据船名获取绑定船员列表，无分页
     *
     * @param dsBoatBindCrewDTO:
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2024/12/18 14:15
     */
    @Override
    public List<DsBoatBindCrew> findBoatBindCrewByBoatName(DsBoatBindCrewDTO dsBoatBindCrewDTO) {
        LambdaQueryWrapper<DsBoatBindCrew> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DsBoatBindCrew::getBoatName1, dsBoatBindCrewDTO.getBoatName())
                .or()
                .eq(DsBoatBindCrew::getBoatName2, dsBoatBindCrewDTO.getBoatName());
        return this.list(wrapper);
    }

    /**
     * 不分页查询船员绑定渔船数据
     *
     * @param dsBoatBindCrewDTO:
     * @return java.util.List<com.ltgk.boat.domain.entity.DsBoatBindCrew>
     * @author Qi ChengBin
     * @date 2024/12/18 14:20
     */
    @Override
    public List<DsBoatBindCrew> findBoatBindCrewList(DsBoatBindCrewDTO dsBoatBindCrewDTO) {
        String boatName = dsBoatBindCrewDTO.getBoatName();
        DsBoatBindCrew dsBoatBindCrew = new DsBoatBindCrew();
        BeanUtils.copyProperties(dsBoatBindCrewDTO, dsBoatBindCrew);

        LambdaQueryWrapper<DsBoatBindCrew> wrapper = new LambdaQueryWrapper<>(dsBoatBindCrew);
        if (StringUtils.isNotBlank(boatName)) {
            wrapper.eq(DsBoatBindCrew::getBoatName1, boatName)
                    .or()
                    .eq(DsBoatBindCrew::getBoatName2, boatName);
        }
        return this.list(wrapper);
    }

    /**
     * 移动端渔船绑定船员
     *
     * @param dto:
     * @return boolean
     * @author Qi ChengBin
     * @date 2024/12/18 14:54
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean addByApp(DsBoatBindCrewDTO dto) {
        SysUser user = SecurityUtils.getLoginUser().getUser();

        // 船名号 数据验证
        String boatName1 = dto.getBoatName1();
        String boatName2 = dto.getBoatName2();
        if (StringUtils.isNotBlank(boatName1) || StringUtils.isNotBlank(boatName2)) {
            LambdaQueryWrapper<DsBoatData> dsBoatDataLambdaQueryWrapper = new LambdaQueryWrapper<>();
            dsBoatDataLambdaQueryWrapper.eq(StringUtils.isNotBlank(boatName1), DsBoatData::getBoatName, boatName1)
                    .or()
                    .eq(StringUtils.isNotBlank(boatName2), DsBoatData::getBoatName, boatName2);
            DsBoatData dsBoatData = dsBoatDataService.getOne(dsBoatDataLambdaQueryWrapper);
            if (Objects.isNull(dsBoatData)) {
                throw new RuntimeException("系统中没有船名号为" + boatName1 + " 或者 " + boatName2 + "的船，请见车船名号是否录入有误");
            }
        }

        // 船员基本信息判断
        if (StringUtils.isBlank(dto.getCrewName())
                || StringUtils.isBlank(dto.getCrewPhone())
                || StringUtils.isBlank(dto.getCrewIdcard())) {
            throw new RuntimeException("船员主要信息不能为空！");
        }

        /*
         * 船员跟角色有关；
         *   如果系统中没有此船员信息，要进行添加，并且赋值角色信息
         *   存在的情况下要进行更新数据
         *   此处是默认系统中有此用户的操作
         * */
        // 判断船员是否存在  TODO: 等保测评情况下身份证号在数据库中需要进行加密，所以查询的时候也要进行加密查询
        LambdaQueryWrapper<DsBoatCrew> dsBoatCrewLambdaQueryWrapper = new LambdaQueryWrapper<>();
        dsBoatCrewLambdaQueryWrapper.eq(DsBoatCrew::getIdCardNo, dto.getCrewIdcard());
        DsBoatCrew dbDsBoatCrew = dsBoatCrewService.getOne(dsBoatCrewLambdaQueryWrapper);
        // 保存/更新 船员信息
        if (Objects.isNull(dbDsBoatCrew)) {
            DsBoatCrew dsBoatCrew = new DsBoatCrew()
                    .setCrewName(dto.getCrewName())
                    .setCrewNamePy(PinyinUtil.getPinyin(dto.getCrewName(), " "))
                    // 性别 1男 2女  工具返回的 男的为1 女的为0
                    .setSex(1 == IdcardUtil.getGenderByIdCard(dto.getCrewIdcard()) ? "1" : "2")
                    .setBirthday(IdcardUtil.getBirthDate(dto.getCrewIdcard()))
                    .setAge(IdcardUtil.getAgeByIdCard(dto.getCrewIdcard()))
                    .setCreateBy(user.getNickName())
                    .setCreateAt(new Date())
                    .setUpdateBy(user.getNickName())
                    .setUpdateAt(new Date())
                    .setPhone(dto.getCrewPhone())
                    .setIdCardNo(dto.getCrewIdcard())
                    .setCertificateCode(dto.getCertificateCode())
                    .setBoatDutyName(dto.getCrewPosition());
            dsBoatCrewService.save(dsBoatCrew);
            dbDsBoatCrew = dsBoatCrew;
            // 根据船员手机号查询系统中的用户信息 TODO：：等保测评情况下手机号在数据库中需要进行加密，所以查询的时候也要进行加密查询
            SysUser dbCrewUser = sysUserService.lambdaQuery()
                    .eq(SysUser::getPhonenumber, dsBoatCrew.getPhone())
                    .one();
            // 绑定船员用户的角色信息，没有这个船员用户则不管
            if (Objects.nonNull(dbCrewUser)) {
                // 获取船员角色信息
                SysRole sysRole = sysRoleService.lambdaQuery()
                        .eq(SysRole::getRoleKey, Constants.CREW)
                        .one();

                List<SysRole> roleList = sysRoleService.selectRolesByUserId(dbCrewUser.getUserId());
                roleList.add(sysRole);
                Long[] roleIds = roleList.stream().map(SysRole::getRoleId).toArray(Long[]::new);
                sysUserService.insertUserAuth(dbCrewUser.getUserId(), roleIds);
            }
        }

        String crewId = dbDsBoatCrew.getId();

//        // 判断该船员是否已被绑定，已经绑定的船员在未解绑之前不能再次绑定
//        LambdaQueryWrapper<DsBoatBindCrew> dsBoatBindCrewLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        dsBoatBindCrewLambdaQueryWrapper.eq(DsBoatBindCrew::getCrewId, crewId);
//        DsBoatBindCrew dbDsBoatBindCrew = this.getOne(dsBoatBindCrewLambdaQueryWrapper);
//        if (Objects.nonNull(dbDsBoatBindCrew)) {
//            throw new RuntimeException("船员‘" + dto.getCrewName() + "’已被" + dbDsBoatBindCrew.getBoatName1() + "绑定，请重新添加船员信息");
//        }

        // 新增渔船绑定船员信息
        DsBoatBindCrew dsBoatBindCrew = new DsBoatBindCrew();
        BeanUtils.copyProperties(dto, dsBoatBindCrew);
        dsBoatBindCrew.setBindTime(new Date())
                .setOwnerPhone(user.getPhonenumber())
                .setCrewId(String.valueOf(crewId))
                .setCreateBy(user.getNickName())
                .setCreateAt(new Date())
                .setUpdateBy(user.getNickName())
                .setUpdateAt(new Date())
                .setDelFlag(Constants.FLAG_FALSE)
        ;
        return this.save(dsBoatBindCrew);
    }

    /**
     * 根据船员ID解除渔船与船员关系
     *
     * @param dsBoatBindCrewDTO:
     * @return boolean
     * @author Qi ChengBin
     * @date 2024/12/18 17:37
     */
    @Override
    public boolean unBindBoatToCrew(DsBoatBindCrewDTO dsBoatBindCrewDTO) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        String crewId = dsBoatBindCrewDTO.getCrewId();
        DsBoatCrew dsBoatCrew = dsBoatCrewService.getById(crewId);
        if (Objects.isNull(dsBoatCrew)) {
            throw new RuntimeException("船员信息不存在！");
        }

        DsBoatBindCrewDTO dto = new DsBoatBindCrewDTO()
                .setCrewName(dsBoatCrew.getCrewName());
        List<DsBoatBindCrew> boatBindCrewByLoginUserAndCrew = findBoatBindCrewByLoginUser(dto);

        if (CollectionUtils.isEmpty(boatBindCrewByLoginUserAndCrew)) {
            throw new RuntimeException("此船员没有绑定您经营的船，您无权解绑！");
        }

        Map<String, DsBoatBindCrew> dsBoatBindCrewMap = boatBindCrewByLoginUserAndCrew.stream().collect(Collectors.toMap(DsBoatBindCrew::getCrewId, v -> v));

        // 更新数据
        LambdaUpdateWrapper<DsBoatBindCrew> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(DsBoatBindCrew::getDelFlag, Constants.FLAG_TRUE)
                // 解绑时间，最后的更新时间
                .set(DsBoatBindCrew::getUpdateAt, new Date())
                // 解绑者，最后的更新用户
                .set(DsBoatBindCrew::getUpdateBy, user.getNickName())
                .eq(DsBoatBindCrew::getId, dsBoatBindCrewMap.get(crewId).getId());
        return this.update(updateWrapper);
    }

    /**
     * 根据登录用户查询跟登录用户相关的船员信息；登录用户所拥有渔船下绑定的船员信息
     *
     * @param dto:
     * @return com.ltgk.common.core.domain.AjaxResult
     * @author Qi ChengBin
     * @date 2025/3/27
     */
    @Override
    public List<DsBoatBindCrew> findBoatBindCrewByLoginUser(DsBoatBindCrewDTO dto) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        List<DsBoatData> dsBoatDataList = dsBoatDataService.lambdaQuery()
                .eq(DsBoatData::getOperatorUserId, user.getUserId())
                .list();

        if (CollectionUtils.isNotEmpty(dsBoatDataList)) {
            Set<String> boatNameSet = dsBoatDataList.stream()
                    .map(DsBoatData::getBoatName)
                    .collect(Collectors.toSet());
            return this.lambdaQuery()
                    .and(
                            wrapper -> wrapper.in(DsBoatBindCrew::getBoatName1, boatNameSet)
                                    .or()
                                    .in(DsBoatBindCrew::getBoatName2, boatNameSet)
                    )
                    .like(DsBoatBindCrew::getCrewName, dto.getCrewName())
                    .list();
        }

        return Collections.emptyList();
    }
}
