package com.ylx.massage.service.impl;


import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONException;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylx.common.config.WechatAccountConfig;
import com.ylx.common.constant.MassageConstants;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.StringUtils;
import com.ylx.massage.domain.TComment;
import com.ylx.massage.domain.TJs;
import com.ylx.massage.domain.TSign;
import com.ylx.massage.domain.TWxUser;
import com.ylx.massage.domain.vo.TJsVo;
import com.ylx.massage.enums.JsStatusEnum;
import com.ylx.massage.mapper.TJsMapper;
import com.ylx.massage.service.TCommentService;
import com.ylx.massage.service.TJsService;
import com.ylx.massage.service.TSignService;
import com.ylx.massage.service.TWxUserService;
import com.ylx.massage.utils.DateTimeUtils;
import com.ylx.massage.utils.LocationUtil;
import com.ylx.massage.utils.VirtualTechnicianNicknameGenerator;
import com.ylx.massage.utils.WeChatUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 技师表 服务实现类
 */
@Service
@Slf4j
public class TJsServiceImpl extends ServiceImpl<TJsMapper, TJs> implements TJsService {
    @Resource
    private TJsMapper mapper;

    @Resource
    private WechatAccountConfig wxPayProperties;

    @Resource
    private LocationUtil locationUtil;

    @Resource
    private TCommentService commentService;

    @Resource
    private TWxUserService wxUserService;

    @Resource
    private WeChatUtil weChatUtil;

    @Resource
    private TSignService signService;

    @Resource(name = "commonAsyncExecutor")
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Resource
    private VirtualTechnicianNicknameGenerator nicknameGenerator;


    @Override
    public Page<TJs> getAll(Page<TJs> page, TJsVo param) {
        return mapper.getAll(page, param);
    }

    @Override
    public boolean addJs(TJs js) {
        LambdaQueryWrapper<TJs> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TJs::getcOpenId, js.getcOpenId());
        TJs cjs = this.getOne(queryWrapper);
        if (cjs != null) {
            throw new ServiceException("请勿重复申请");
        }
//        cacheAddress(js);
        initialization(js);
        return this.save(js);
    }

    private void cacheAddress(TJs js) {
        if (StringUtils.isBlank(js.getcPhone())) {
            throw new ServiceException("手机号不能为空");
        }
        if (StringUtils.isBlank(js.getName())) {
            throw new ServiceException("地址不能为空");
        }
        if (StringUtils.isNotBlank(js.getId())) {
            TJs oldJs = this.getById(js.getId());
            if (oldJs.getnTong().equals(JsStatusEnum.JS_RETURN.getCode())) {
                js.setnTong(JsStatusEnum.JS_NOT_PASS.getCode());
            }
        }
        if (StringUtils.isNotBlank(js.getName())) {
            this.updateLocation(js);
        }
//        log.info("js:{}", js);
//        JSONObject jsonObject = new JSONObject(js.getcAddress());
//        Object latitude = jsonObject.get("latitude");
//        Object longitude = jsonObject.get("longitude");
//        locationUtil.geoAdd(LocationUtil.GEO_KEY,js.getcOpenId(), Double.parseDouble(js.getLongitude().toString()), Double.parseDouble(js.getLatitude().toString()));
    }


    @Override
    public boolean wxUpdateJs(TJs js) {
        cacheAddress(js);
        return this.updateById(js);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean auditing(TJs js) {
        TJs js1 = this.getById(js.getId());

        LambdaQueryWrapper<TJs> jsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        jsLambdaQueryWrapper.eq(TJs::getId, js.getId()).eq(TJs::getnTong, JsStatusEnum.JS_NOT_PASS.getCode());
        js.setnTong(JsStatusEnum.JS_PASS.getCode());
        js.setnB2(1);
        js.setcPhone(js1.getcPhone());
        js.setcTime(new Date());

        LambdaQueryWrapper<TWxUser> wxLambdaQueryWrapper = new LambdaQueryWrapper<>();
        wxLambdaQueryWrapper.eq(TWxUser::getcOpenid, js1.getcOpenId());
        TWxUser tWxUser = new TWxUser();
        //角色状态修改
        tWxUser.setRole(1);
        wxUserService.update(tWxUser, wxLambdaQueryWrapper);
        //修改审核状态
        boolean update = this.update(js, jsLambdaQueryWrapper);

        //修改新技师标识
       /* js.setcOpenId(js1.getcOpenId());
        // 发送审核结果通知
        this.jsNotification(js);*/
        return update;
    }

    @Override
    public void jsNotification(TJs js) {
        try {
            cn.hutool.json.JSONObject param = JSONUtil.createObj();
            //是否审核通过

            if (JsStatusEnum.JS_PASS.getCode().equals(js.getnTong())) {
                param.set("const1", JSONUtil.createObj().set("value", "审核通过可以接单"));
            } else {
                param.set("const1", JSONUtil.createObj().set("value", "审核驳回请重新提交"));
            }

            //审核时间
            param.set("time2", JSONUtil.createObj().set("value", DateTimeUtils.formatDate(new Date(), DateTimeUtils.DATE_NUMBER_YEAR_MONTH_FORMAT)));
            //账号
            param.set("character_string3", JSONUtil.createObj().set("value", js.getcPhone()));
            //
            weChatUtil.notification(js.getcOpenId(), wxPayProperties.getTemplateId2(), param);
        } catch (JSONException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }

    @Override
    public boolean updateLocation(TJs js) {
        if (StringUtils.isBlank(js.getId())) {
            throw new ServiceException("ID不能为空");
        }
        if (StringUtils.isBlank(js.getName())) {
            throw new ServiceException("地址不能为空");
        }
//        JSONObject jsonObject = new JSONObject(js.getcAddress());
//        Object latitude = jsonObject.get("latitude");
//        Object longitude = jsonObject.get("longitude");
        locationUtil.geoAdd(LocationUtil.GEO_KEY, js.getcPhone(), Double.parseDouble(js.getLongitude().toString()), Double.parseDouble(js.getLatitude().toString()));
        return this.updateById(js);
    }

    @Override
    public void newOrderNotification(String openId) {
//        订单号 23010000010101
//        用户电话 15055556666
//        用户名称 李四
//        时间 2022年11月11日22:22
//        服务地址 湖南长沙岳麓

        /*cn.hutool.json.JSONObject param = JSONUtil.createObj();
        //订单号
        param.set("character_string9", JSONUtil.createObj().set("value", "23010000010101"));
        //点话
        param.set("phone_number14", JSONUtil.createObj().set("value", "18360233903"));
        param.set("thing18", JSONUtil.createObj().set("value", "李四"));
        param.set("time6", JSONUtil.createObj().set("value", "2022年11月11日 22:22"));
        param.set("thing27", JSONUtil.createObj().set("value", "湖南长沙岳麓"));*/

        cn.hutool.json.JSONObject param = JSONUtil.createObj();
        /**
         * 接单成功通知
         */
        //设置订单号
        param.set("character_string1", JSONUtil.createObj().set("value", "123456"));
        //设置项目
        param.set("thing4", JSONUtil.createObj().set("value", "按摩"));
        //商家名称
        param.set("thing9", JSONUtil.createObj().set("value", "李强"));
        //联系电话
        param.set("phone_number5", JSONUtil.createObj().set("value", "15296619636"));
        weChatUtil.notification(openId, wxPayProperties.getUserTemplate1(), param);

    }

    @Override
    public boolean upPost(TJs js) {

        if (StringUtils.isBlank(js.getId())) {
            throw new ServiceException("技师ID不能为空");
        }
        if (js.getnStatus2() == null) {
            throw new ServiceException("岗位状态不能为空");
        }
        TJs js2 = this.getById(js.getId());
        TSign tSign = new TSign();

        //上岗
        if (Objects.equals(js.getnStatus2(), JsStatusEnum.POST_ON_DUTY.getCode())) {
            //岗位状态为1时，设置nStatus为1
            js.setnStatus(JsStatusEnum.JS_SERVICEABLE.getCode());
            //记录签到信息
            tSign.setSingTime(new Date());
            tSign.setOpenId(js2.getcOpenId());
            tSign.setJsId(js2.getId());
            tSign.setName(js2.getcName());
            tSign.setDeptId(js2.getDeptId());
            tSign.setDeptName(js2.getCity());
            signService.save(tSign);
        }
        if (Objects.equals(js.getnStatus2(), JsStatusEnum.POST_NOT_ON_DUTY.getCode())) {

            //判断该技师是否有服务中的订单
            TJs js1 = this.getById(js.getId());
            if (js1.getnStatus().equals(JsStatusEnum.JS_SERVICE.getCode())) {
                throw new ServiceException("您有服务中的订单，不能下岗");
            }
            js.setnStatus(JsStatusEnum.JS_NO_SERVICE.getCode());
            LambdaQueryWrapper<TSign> signLambdaQueryWrapper = new LambdaQueryWrapper<>();
            signLambdaQueryWrapper.eq(TSign::getJsId, js.getId()).isNull(TSign::getLayoffTime).orderByAsc(TSign::getSingTime).last("LIMIT 1");
            TSign singn = signService.getOne(signLambdaQueryWrapper);

            if (null != singn) {
                singn.setLayoffTime(new Date());
                Long time = getaTime(singn);
                singn.setOnlineTime(time.intValue());
                signService.updateById(singn);
            }
//            else {
//                tSign.setSingTime(DateTimeUtils.getStartDate(new Date()));
//                tSign.setLayoffTime(new Date());
//                tSign.setOpenId(js2.getcOpenId());
//                tSign.setJsId(js2.getId());
//                tSign.setName(js2.getcName());
//                Long time = getaTime(tSign);
//                tSign.setDeptId(js2.getDeptId());
//                tSign.setDeptName(js2.getCity());
//                tSign.setOnlineTime(time.intValue());
//                signService.save(tSign);
//            }
        }
        return this.updateById(js);
    }

    private Long getaTime(TSign tSign) {
        Long layoff = DateTimeUtils.dateToStamp(tSign.getLayoffTime());
        Long sing = DateTimeUtils.dateToStamp(tSign.getSingTime());
        Long time = layoff - sing;
        time = time / 1000;
        time = time / 60;
        return time;
    }

    @Override
    public boolean block(TJs js) {
        if (StringUtils.isBlank(js.getId())) {
            throw new ServiceException("技师ID不能为空");
        }
        if (js.getnTong() == null) {
            throw new ServiceException("拉黑状态不能为空");
        }
        //恢复
        if (Objects.equals(js.getnTong(), JsStatusEnum.JS_NOT_PASS.getCode())) {
            //岗位状态为1时，设置nStatus为1
            js.setnStatus(JsStatusEnum.JS_NO_SERVICE.getCode());
        }
        if (Objects.equals(js.getnTong(), JsStatusEnum.BLOCKED.getCode())) {

            //判断该技师是否有服务中的订单
            TJs js1 = this.getById(js.getId());
            if (js1.getnStatus().equals(JsStatusEnum.JS_SERVICE.getCode())) {
                throw new ServiceException("有服务中的订单，暂时不能拉黑");
            }
            js.setnStatus(JsStatusEnum.JS_NO_SERVICE.getCode());
            js.setnStatus2(JsStatusEnum.POST_NOT_ON_DUTY.getCode());
        }
        return this.updateById(js);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean pcAddJs(TJs js) {
        /*if (js.getCity() == null) {
            throw new ServiceException("所在城市不能为空");
        }*/
        //判断生活照图片列表不能为空
        if (js.getcImgList() == null || js.getcImgList().isEmpty()) {
            throw new ServiceException("生活照图片列表不能为空");
        }
        //判断身份证图片列表不能为空
        if (js.getcSfzImg() == null || js.getcSfzImg().isEmpty()) {
            throw new ServiceException("身份证图片列表不能为空");
        }

        //判断虚拟订单数量不能为空
        if (js.getVirtualOrderNumber() == null) {
            throw new ServiceException("虚拟订单数量不能为空");
        }

        if (js.getVirtualTechNumber() == null) {
            // 默认值为10
            js.setVirtualTechNumber(10);
        }

        // 验证虚拟技师数量
        Integer virtualTechNumber = js.getVirtualTechNumber();
        if (virtualTechNumber < 0) {
            throw new ServiceException("虚拟技师数量不能为负数");
        }

        // 0-真实技师
        js.setTechType(0);
        //设置性别，默认：女
        js.setnSex(0);
        //设置服务状态，默认：可服务
        js.setnStatus(JsStatusEnum.JS_SERVICEABLE.getCode());
        // 上岗状态：默认为未上岗
        js.setnStatus2(JsStatusEnum.POST_NOT_ON_DUTY.getCode());
        // 审核状态：默认为待审核
        js.setnTong(JsStatusEnum.JS_NOT_PASS.getCode());
        js.setDtCreateTime(LocalDateTime.now());
        this.save(js);

        // 如果需要生成虚拟技师
        if (virtualTechNumber > 0) {
            log.info("开始为真实技师[{}]生成{}个虚拟技师", js.getcName(), virtualTechNumber);
            generateVirtualTechnicians(js, virtualTechNumber);
        }

        String token = weChatUtil.getToken();
        log.info("获取到的token: {}", token);
        //获取二维码ticket
        Map<?, ?> jsTicket = weChatUtil.getJsTicket(token, js.getId());
        log.info("获取到的jsTicket: {}", jsTicket);
        js.setTicket(jsTicket.get("ticket").toString());
        return this.updateById(js);
    }

    /**
     * 批量生成虚拟技师
     * <p>
     * 业务规则：
     * <ul>
     *   <li>虚拟技师类型为 techType = 1</li>
     *   <li>除昵称外，其他信息与真实技师完全一致</li>
     *   <li>昵称随机生成（2-3个汉字，偏女性化，全表唯一）</li>
     *   <li>虚拟技师不需要手机号、OpenID等敏感信息</li>
     * </ul>
     * </p>
     *
     * @param realTechnician 真实技师信息
     * @param virtualTechNumber 需要生成的虚拟技师数量
     */
    private void generateVirtualTechnicians(TJs realTechnician, Integer virtualTechNumber) {
        try {
            // 批量生成唯一昵称
            List<String> nicknames = nicknameGenerator.batchGenerateUniqueNicknames(virtualTechNumber);
            log.info("成功生成{}个唯一昵称", nicknames.size());

            // 批量创建虚拟技师对象
            List<TJs> virtualTechnicians = new ArrayList<>(virtualTechNumber);
            LocalDateTime now = LocalDateTime.now();

            for (String nickname : nicknames) {
                TJs virtualJs = new TJs();

                // 复制真实技师的所有字段（除ID、昵称、技师类型外）
                virtualJs.setcNickName(nickname); // 随机生成的昵称
                virtualJs.setTechType(1); // 1-虚拟技师
                virtualJs.setcName(realTechnician.getcName()); // 真实姓名（保持一致）
                virtualJs.setcPortrait(realTechnician.getcPortrait()); // 头像
                virtualJs.setcPhone(realTechnician.getcPhone());
                virtualJs.setcOpenId(realTechnician.getcOpenId());
                virtualJs.setcAddress(realTechnician.getcAddress()); // 地址
                virtualJs.setnSex(realTechnician.getnSex()); // 性别
                virtualJs.setcImgList(realTechnician.getcImgList()); // 生活照列表
                virtualJs.setcSfzImg(realTechnician.getcSfzImg()); // 身份证图片
                virtualJs.setcVideo(realTechnician.getcVideo()); // 视频介绍
                virtualJs.setcBhList(realTechnician.getcBhList()); // 可预约项目列表
                virtualJs.setHealthCertificate(realTechnician.getHealthCertificate()); // 健康证
                virtualJs.setBusinessLicense(realTechnician.getBusinessLicense()); // 营业执照
                virtualJs.setCertification(realTechnician.getCertification()); // 资格证
                virtualJs.setNoCrime(realTechnician.getNoCrime()); // 无犯罪记录
                virtualJs.setDeptId(realTechnician.getDeptId()); // 部门ID
                virtualJs.setDaytimeMileage(realTechnician.getDaytimeMileage()); // 白天免车费公里数
                virtualJs.setNigthMileage(realTechnician.getNigthMileage()); // 夜间免车费公里数
                virtualJs.setcJianjie(realTechnician.getcJianjie()); // 个人简介
                virtualJs.setnStar(MassageConstants.INTEGER_FIVE); // 评分
                virtualJs.setnBili(realTechnician.getnBili()); // 佣金比例
                virtualJs.setLongitude(realTechnician.getLongitude()); // 经度
                virtualJs.setLatitude(realTechnician.getLatitude()); // 纬度
                // 服务状态，默认：可服务
                virtualJs.setnStatus(JsStatusEnum.JS_SERVICEABLE.getCode());
                virtualJs.setnStatus2(JsStatusEnum.POST_NOT_ON_DUTY.getCode()); // 上岗状态
                virtualJs.setnTong(JsStatusEnum.JS_NOT_PASS.getCode()); // 审核状态
                virtualJs.setnB1(realTechnician.getnB1());
                virtualJs.setnB2(realTechnician.getnB2());
                virtualJs.setnB3(realTechnician.getnB3());
                virtualJs.setDtCreateTime(now); // 创建时间
                virtualJs.setVirtualOrderNumber(realTechnician.getVirtualOrderNumber()); // 虚拟订单数量
                virtualJs.setVirtualTechNumber(0); // 虚拟技师数量（虚拟技师不再生成虚拟技师）
                virtualJs.setRecording(realTechnician.getRecording()); // 录音
                virtualJs.setVideoRecording(realTechnician.getVideoRecording()); // 录像
                virtualJs.setCommitment(realTechnician.getCommitment()); // 承诺书
                virtualJs.setCity(realTechnician.getCity()); // 所在城市
                virtualJs.setJsGrade(realTechnician.getJsGrade()); // 技师等级
                virtualTechnicians.add(virtualJs);
            }

            // 批量保存虚拟技师
            boolean saveResult = this.saveBatch(virtualTechnicians);
            if (saveResult) {
                log.info("成功批量保存{}个虚拟技师", virtualTechnicians.size());
            } else {
                throw new ServiceException("批量保存虚拟技师失败");
            }
        } catch (Exception e) {
            log.error("生成虚拟技师失败", e);
            throw new ServiceException("生成虚拟技师失败：" + e.getMessage());
        } finally {
            // 清理昵称缓存，释放内存
            nicknameGenerator.clearCache();
        }
    }

    @Override
    public TJs getByJsId(String jsId, String openId) {
        if (jsId == null || jsId.trim().isEmpty()) {
            // 处理空或空白的jsId
            throw new ServiceException("Id为空");
        }
        TJs js = this.getById(jsId);
        if (js == null) {
            // 处理getById返回null的情况
            return null; // 或者返回一个新的TJs实例，具体看业务需求
        }
        if (StringUtils.isBlank(js.getcBhList())) {
            // 处理js.getcBhList()返回null或空列表的情况
            js.setProjects(new ArrayList<>()); // 设置空列表，避免后续调用空指针
            return js;
        }
        //查询项目
//        List<String> projectIds = Arrays.stream(js.getcBhList().split(",")).collect(Collectors.toList());
//        LambdaQueryWrapper<TXiangmu> xiangmuLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        xiangmuLambdaQueryWrapper.in(TXiangmu::getcId, projectIds).orderByAsc(TXiangmu::getdPrice);
//        List<TXiangmu> projects = xiangmuService.list(xiangmuLambdaQueryWrapper);
//        js.setProjects(projects);
        //查询评论
        LambdaQueryWrapper<TComment> commentLambdaQueryWrapper = new LambdaQueryWrapper<>();
        commentLambdaQueryWrapper.eq(TComment::getcJsid, jsId);
        List<TComment> list = commentService.list(commentLambdaQueryWrapper);
        if (CollectionUtil.isNotEmpty(list)) {
            js.setComments(list);
        }
        //是否收藏
//        LambdaQueryWrapper<TCollect> objectLambdaQueryWrapper = new LambdaQueryWrapper<>();
//        objectLambdaQueryWrapper.eq(TCollect::getcJsId, jsId).eq(TCollect::getcWxOpenId, openId);
//        TCollect collect = collectService.getOne(objectLambdaQueryWrapper);
//        if (collect != null) {
//            js.setIsCollection(true);
//        } else {
//            js.setIsCollection(false);
//        }
        return js;
    }


    private static void initialization(TJs js) {
        // 评分默认最高 5
        js.setnStar(MassageConstants.INTEGER_FIVE);
        // 已服务数量 0
        js.setnNum(MassageConstants.INTEGER_ZERO);
        // 佣金比例 10
        js.setnBili(MassageConstants.INTEGER_TEN);
        // 服务状态
        js.setnStatus(JsStatusEnum.JS_NO_SERVICE.getCode());
        // 上岗状态
        js.setnStatus2(JsStatusEnum.POST_NOT_ON_DUTY.getCode());
        // 审核状态
        js.setnTong(JsStatusEnum.JS_NOT_PASS.getCode());
        js.setnB1(MassageConstants.INTEGER_ZERO);
        js.setnB2(MassageConstants.INTEGER_ZERO);
        js.setnB3(MassageConstants.INTEGER_ZERO);
        js.setTechType(MassageConstants.INTEGER_ZERO);
        js.setDtCreateTime(LocalDateTime.now());
    }
}
