package com.ylx.web.controller.massage;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ylx.common.annotation.Log;
import com.ylx.common.core.controller.BaseController;
import com.ylx.common.core.domain.R;
import com.ylx.common.core.domain.model.LoginUser;
import com.ylx.common.core.domain.model.WxLoginUser;
import com.ylx.common.enums.BusinessType;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.ListUtils;
import com.ylx.massage.domain.Location;
import com.ylx.massage.domain.TJs;
import com.ylx.massage.domain.vo.TJsVo;
import com.ylx.massage.enums.JsStatusEnum;
import com.ylx.massage.service.TJsService;
import com.ylx.massage.service.TWxUserService;
import com.ylx.massage.utils.LocationUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.common.error.WxErrorException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.*;

/**
 * 技师Controller
 *
 * @author ylx
 * @date 2024-03-22
 */
@RestController
@RequestMapping("api/js/v1")
@Api(tags = {"技师管理"})
@Slf4j
public class TJsController extends BaseController {
    @Resource
    private TJsService jsService;

    @Resource
    private LocationUtil locationUtil;

    @Resource
    private TWxUserService wxUserService;

    @Autowired
    private WxMaService wxMaService;

    @Value("${wx.template_id_1}")
    private String msgTemplateId1;


    /**
     * 添加技师申请
     *
     * @param js
     * @return R
     */
    @Log(title = "技师管理", businessType = BusinessType.INSERT)
    @RequestMapping(value = "wx/add", method = RequestMethod.POST)
    @ApiOperation("添加技师申请")
    public R add(@RequestBody TJs js) {
        try {
            WxLoginUser wxLoginUser = getWxLoginUser();
            js.setcOpenId(wxLoginUser.getCOpenid());
            return R.ok(jsService.addJs(js));
        } catch (ServiceException s) {
            log.error(s.toString());
            return R.fail(s.getMessage());
        }
    }


    /**
     * PC端添加技师
     *
     * @param js
     * @return R
     */
    @Log(title = "技师管理", businessType = BusinessType.INSERT)
    @RequestMapping(value = "pc/add", method = RequestMethod.POST)
    @ApiOperation("PC添加技师申请")
    public R pcAdd(@RequestBody TJs js) {
        try {
            return R.ok(jsService.pcAddJs(js));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 更新技师信息
     *
     * @param js
     * @return R
     */
    @Log(title = "技师管理", businessType = BusinessType.UPDATE)
    @RequestMapping(value = "wx/update", method = RequestMethod.POST)
    @ApiOperation("更新技师信息")
    public R wxUpdate(@RequestBody TJs js) {
        try {
            return R.ok(jsService.wxUpdateJs(js));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }


    /**
     * 实时更新技师位置
     *
     * @param js
     * @return R 更新结果
     */
    @Log(title = "实时更新技师位置", businessType = BusinessType.UPDATE)
    @RequestMapping(value = "wx/updateLocation/f", method = RequestMethod.POST)
    @ApiOperation("实时更新技师位置")
    public R updateLocation(@RequestBody TJs js) {
        try {
            return R.ok(jsService.updateLocation(js));
        } catch (ServiceException s) {
            s.printStackTrace();
            log.error(s.toString());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            log.error(e.toString());
            return R.fail("系统异常");
        }
    }

    /**
     * 免车费设置
     *
     * @param js
     * @return R
     */
    @Log(title = "免车费设置", businessType = BusinessType.UPDATE)
    @RequestMapping(value = "wx/freeFare", method = RequestMethod.POST)
    @ApiOperation("免车费设置")
    public R freeFare(@RequestBody TJs js) {
        try {
            return R.ok(jsService.updateById(js));
        } catch (ServiceException s) {
            log.error(s.toString());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            log.error(e.toString());
            return R.fail("系统异常");
        }
    }

    /**
     * 上岗/下岗
     *
     * @param js
     * @return R
     */
    @Log(title = "上岗/下岗", businessType = BusinessType.UPDATE)
    @RequestMapping(value = "wx/post", method = RequestMethod.POST)
    @ApiOperation("上岗/下岗")
    public R upPost(@RequestBody TJs js) {
        try {
            return R.ok(jsService.upPost(js));
        } catch (ServiceException s) {
            log.error(s.toString());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            log.error(e.toString());
            return R.fail("系统异常");
        }
    }


    /**
     * 解绑微信账号
     *
     * @param id
     * @return R
     */
    @Log(title = "解绑", businessType = BusinessType.UPDATE)
    @RequestMapping(value = "pc/unbind", method = RequestMethod.GET)
    @ApiOperation("技师解绑")
    public R unbind(@RequestParam String id) {
        try {
            return R.ok(jsService.update(new LambdaUpdateWrapper<TJs>().eq(TJs::getId, id).set(TJs::getcOpenId, null)));
        } catch (ServiceException s) {
            log.error(s.toString());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            log.error(e.toString());
            return R.fail("系统异常");
        }
    }


    /**
     * 微信查询技师列表（用户端）
     *
     * @param page 分页参数
     * @param js
     * @return R 技师列表
     */
    @RequestMapping(value = "wx/select", method = RequestMethod.GET)
    @ApiOperation("微信查询技师列表")
    public R wxSelect(Page<TJs> page, TJsVo js) {
        try {
            log.info("微信查询技师列表，请求参数:{}", JSON.toJSONString(js));
            /*if (js.getLatitude() != null && js.getLongitude() != null) {
                // 检查经纬度是否在合理范围内
                Location location = new Location();
                location.setLatitude(js.getLatitude().doubleValue());
                location.setLongitude(js.getLongitude().doubleValue());
                location.setLimit(100L); // 考虑将此值作为参数或配置项
                location.setRadius(1000.00);
                List<TJs> nearbyTechnicians = locationUtil.dis(location);
                log.info("附近的技师：{}",JSON.toJSONString(nearbyTechnicians));

                if (nearbyTechnicians != null) {
                    Map<String, BigDecimal> collect = nearbyTechnicians.stream().collect(Collectors.toMap(TJs::getcPhone, TJs::getDistance));
                    js.setIds(nearbyTechnicians.stream().map(TJs::getcPhone).collect(Collectors.toList()));
                    log.info("缓存技师:{}", JSONUtil.toJsonStr(nearbyTechnicians.stream().map(TJs::getcPhone).collect(Collectors.toList())));

                    int pageNum = (int) page.getCurrent();
                    int size = (int) page.getSize();

                    Page<TJs> all = jsService.getAll(page, js);
                    log.info("总条数============>:{},当前页:{}", all.getRecords().size(), pageNum);
                    all.getRecords().forEach(item -> {
                        item.setDistance(collect.get(item.getcPhone()).setScale(2, RoundingMode.DOWN));
                    });
                    List<TJs> sortJs = all.getRecords().stream().sorted(Comparator.comparing((TJs t) ->
                            t.getnB1() == 1 ? 0 : 1).// 1 状态优先
                            thenComparing(TJs::getDistance)).collect(Collectors.toList());

                    List<TJs> objects = (List<TJs>) ListUtils.subList(sortJs, size, pageNum);
                    page.setRecords(objects);
                    page.setSize(size);
                    page.setCurrent(pageNum);
                    //log.info("page============>:{}", JSONUtil.toJsonStr(page));
                    return R.ok(page);
                }
            }*/
            return R.ok(jsService.getAll(page, js));
        } catch (Exception e) {
            // 异常处理
            e.printStackTrace();
            return R.fail("操作失败");
        }
    }


    /**
     * 分页查询技师数据（PC端）
     *
     * @param page
     * @param js
     * @return Page<TJs>
     */
    @RequestMapping(value = "/select", method = RequestMethod.GET)
    @ApiOperation("分页查询技师数据")
    public Page<TJs> selectSp(Page<TJs> page, TJs js) {
        LoginUser loginUser = this.getLoginUser();
        log.info("loginUser：{}", JSONUtil.toJsonStr(loginUser));

        LambdaQueryWrapper<TJs> mhCompanyLambdaQueryWrapper = new LambdaQueryWrapper<>();
        mhCompanyLambdaQueryWrapper.
                like(StringUtils.isNotBlank(js.getcName()), TJs::getcName, js.getcName()).
                like(StringUtils.isNotBlank(js.getcNickName()), TJs::getcNickName, js.getcNickName()).
                like(StringUtils.isNotBlank(js.getcPhone()), TJs::getcPhone, js.getcPhone()).
                eq(js.getnStatus() != null, TJs::getnStatus, js.getnStatus()).
                eq(js.getnSex() != null, TJs::getnSex, js.getnSex()).
                eq(js.getDeptId() != null, TJs::getDeptId, js.getDeptId()).
                eq(TJs::getTechType, 0) // 只查询真实技师的
                .orderByDesc(TJs::getDtCreateTime);
        //部门数据
        if (loginUser.getDeptId() != 100) {
            mhCompanyLambdaQueryWrapper.eq(TJs::getDeptId, loginUser.getDeptId().toString());
        }
        //查询技师数据
        if (js.getPageType() == 1) {
            mhCompanyLambdaQueryWrapper.eq(TJs::getnTong, JsStatusEnum.JS_PASS.getCode());
        } else {
            // 查询审核页的数据
            mhCompanyLambdaQueryWrapper.in(TJs::getnTong, Arrays.asList(JsStatusEnum.JS_RETURN.getCode(), JsStatusEnum.JS_NOT_PASS.getCode(), JsStatusEnum.BLOCKED.getCode()));
        }
        return jsService.page(page, mhCompanyLambdaQueryWrapper);
    }


    /**
     * 分页查询可服务的真实技师列表
     *
     * @param page
     * @param js
     * @return R<Page < TJs>>
     */
    @ApiOperation("分页查询可服务的真实技师列表")
    @RequestMapping(value = "/queryRealTechnicians", method = RequestMethod.GET)
    public R<Page<TJs>> page(Page<TJs> page, TJs js) {
        LambdaQueryWrapper<TJs> mhCompanyLambdaQueryWrapper = new LambdaQueryWrapper<>();
        mhCompanyLambdaQueryWrapper.
                like(StringUtils.isNotBlank(js.getcName()), TJs::getcName, js.getcName()).
                eq(TJs::getnStatus, 0).
                eq(TJs::getTechType, 0)
                .eq(TJs::getnTong, JsStatusEnum.JS_PASS.getCode())
                .eq(TJs::getnStatus2, 0)
                .orderByDesc(TJs::getnNum); //已服务数量降序排序
        return R.ok(jsService.page(page, mhCompanyLambdaQueryWrapper));
    }


    /**
     * 删除技师
     *
     * @param js
     * @return Boolean
     */
    @Log(title = "技师管理", businessType = BusinessType.DELETE)
    @RequestMapping(value = "/del", method = RequestMethod.POST)
    @ApiOperation("删除技师")
    public R del(@RequestBody TJs js) {
        boolean b = jsService.removeById(js);
        if (b) {
            return R.ok();
        }
        return R.fail("删除失败");
    }

    /**
     * 根据id查询技师详情
     *
     * @param js
     * @return R
     */
    @ApiOperation("根据id查询技师详情")
    @RequestMapping(value = "/wx/getByid", method = RequestMethod.POST)
    public R getById(@RequestBody TJs js) {
        try {
            return R.ok(jsService.getByJsId(js.getId(), js.getcOpenId()));
        } catch (ServiceException s) {
            log.error(s.getMessage());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
            return R.fail("系统异常");
        }
    }

    /**
     * 根据OpenId查询技师详情
     *
     * @param js
     * @return R
     */
    @ApiOperation("根据OpenId查询技师详情")
    @RequestMapping(value = "/wx/getByOpenId", method = RequestMethod.POST)
    public R getByOpenId(@RequestBody TJs js) {
        try {
            LambdaQueryWrapper<TJs> mhCompanyLambdaQueryWrapper = new LambdaQueryWrapper<>();
            mhCompanyLambdaQueryWrapper.eq(TJs::getcOpenId, js.getcOpenId());
            return R.ok(jsService.getOne(mhCompanyLambdaQueryWrapper));
        } catch (ServiceException s) {
            log.error(s.getMessage());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
            return R.fail("系统异常");
        }
    }

    /**
     * 审核技师
     *
     * @param js
     * @return R
     */
    @ApiOperation("审核技师")
    @RequestMapping(value = "/auditing", method = RequestMethod.POST)
    public R auditing(@RequestBody TJs js) {
        try {
            return R.ok(jsService.auditing(js));
        } catch (ServiceException s) {
            log.error(s.getMessage());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
            return R.fail("系统异常");
        }
    }

    /**
     * 退回
     *
     * @param js
     * @return R
     */
    @ApiOperation("退回")
    @RequestMapping(value = "/repulse", method = RequestMethod.POST)
    public R repulse(@RequestBody TJs js) {
        try {
            TJs js1 = jsService.getById(js.getId());

            LambdaQueryWrapper<TJs> mhCompanyLambdaQueryWrapper = new LambdaQueryWrapper<>();
            mhCompanyLambdaQueryWrapper.eq(TJs::getId, js.getId()).eq(TJs::getnTong, JsStatusEnum.JS_NOT_PASS.getCode());
            js.setnTong(JsStatusEnum.JS_RETURN.getCode());
            boolean update = jsService.update(js, mhCompanyLambdaQueryWrapper);
            js.setcOpenId(js1.getcOpenId());
            js.setcPhone(js1.getcPhone());
            jsService.jsNotification(js);
            return R.ok(update);
        } catch (ServiceException s) {
            log.error(s.getMessage());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
            return R.fail("系统异常");
        }
    }

    /**
     * 拉黑技师
     *
     * @param js
     * @return R
     */
    @ApiOperation("拉黑技师")
    @RequestMapping(value = "/block", method = RequestMethod.POST)
    public R block(@RequestBody TJs js) {
        try {
            return R.ok(jsService.block(js));
        } catch (ServiceException s) {
            log.error(s.getMessage());
            return R.fail(s.getMessage());
        } catch (Exception e) {
            log.error(e.getMessage());
            return R.fail("系统异常");
        }
    }

    @ApiOperation("小程序通知")
    @RequestMapping(value = "/tongzhi", method = RequestMethod.GET)
    public boolean sendSubscribeMessage(String openId) {
        String page = "pages/index/index"; // 应该是消息点击后跳转页面
        WxMaSubscribeMessage message = new WxMaSubscribeMessage();
        message.setTemplateId(msgTemplateId1);
        message.setToUser(openId);
        message.setPage(page);
        List<WxMaSubscribeMessage.MsgData> subscribeDataList = new ArrayList<>();
        WxMaSubscribeMessage.MsgData subscribeData = new WxMaSubscribeMessage.MsgData();
        subscribeData.setName("key1"); // 你在小程序自定义的key(比如“商家名称”)
        subscribeData.setValue("夜来香"); //key对应的内容

        WxMaSubscribeMessage.MsgData msgData = new WxMaSubscribeMessage.MsgData();
        msgData.setName("key2");
        msgData.setValue("");
        //添加你配置要且要展示的内容
        subscribeDataList.add(subscribeData);

        message.setData(subscribeDataList);
        try {
            wxMaService.getMsgService().sendSubscribeMsg(message);
            return true;
        } catch (WxErrorException e) {
            log.error("发送小程序订阅消息失败，errCode:{}，errMsg:{}", e.getError().getErrorCode(), e.getError().getErrorMsg());
        }
        return false;
    }

    /**
     * 服务器号新订单处理通知
     *
     * @param openId
     * @return boolean
     */
    @ApiOperation("公众号新订单处理通知")
    @RequestMapping(value = "/notification", method = RequestMethod.GET)
    public boolean newOrderNotification(String openId) {
        jsService.newOrderNotification(openId);
        return true;
    }
}
