package com.ylx.web.controller.massage;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;

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.constant.CacheConstants;
import com.ylx.common.constant.Constants;
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.core.domain.model.aliyun.SendSmsComponents;
import com.ylx.common.core.page.TableDataInfo;
import com.ylx.common.core.redis.RedisCache;
import com.ylx.common.enums.BusinessType;
import com.ylx.common.exception.user.CaptchaException;
import com.ylx.common.exception.user.CaptchaExpireException;
import com.ylx.common.utils.MessageUtils;
import com.ylx.common.utils.StringUtils;
import com.ylx.common.utils.poi.ExcelUtil;
import com.ylx.framework.manager.AsyncManager;
import com.ylx.framework.manager.factory.AsyncFactory;
import com.ylx.framework.web.service.WxTokenService;
import com.ylx.massage.domain.MaProject;
import com.ylx.massage.domain.MaTechnician;
import com.ylx.massage.domain.TWxUser;
import com.ylx.massage.domain.dto.*;
import com.ylx.massage.domain.vo.*;
import com.ylx.massage.service.IMaProjectService;
import com.ylx.massage.service.IMaTechnicianService;
import com.ylx.massage.service.TWxUserService;
import com.ylx.servicecategory.domain.ServiceCategory;
import com.ylx.servicecategory.service.ServiceCategoryService;
import com.ylx.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.*;

/**
 * 技师Controller
 *
 * @author ylx
 * @date 2024-03-22
 */
@Api("技师管理")
@Slf4j
@RestController
@RequestMapping("/technician/technician")
public class MaTechnicianController extends BaseController {
    @Autowired
    private IMaTechnicianService maTechnicianService;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private SendSmsComponents sendSms;
    @Autowired
    private ServiceCategoryService serviceCategoryService;
    @Autowired
    private IMaProjectService maProjectService;
    @Autowired
    private ISysConfigService configService;
    @Autowired
    private RedisCache redisCache;

    @Autowired
    private WxTokenService wxTokenService;

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Resource
    private TWxUserService wxUserService;


    public static final String PHONE_THREEUSERPARTCLIENT_CODE_KEY = "sys:clientLogin:phone:";


    /**
     * 商户手机号密码登录
     *
     * @param thirdPartyLoginsVo
     * @return R<WxLoginUser>
     */
    @ApiOperation(value = "商户手机号密码登录", notes = "商户手机号密码登录")
    @PostMapping(value = "/clientLogin")
    public R<WxLoginUser> login(@RequestBody ThirdPartyLoginsVo thirdPartyLoginsVo) throws Exception {
        // 校验手机号是否为空
        if (StringUtils.isBlank(thirdPartyLoginsVo.getPhone())) {
            return R.fail("请输入手机号");
        }

        // 校验用户是否存在且有效
        LambdaQueryWrapper<TWxUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(TWxUser::getcPhone, thirdPartyLoginsVo.getPhone()).eq(TWxUser::getRole, 1);

        TWxUser tWxUser = wxUserService.getOne(queryWrapper);
        // 校验用户是否有效
        if (ObjectUtils.isEmpty(tWxUser)) {
            return R.fail("商户不存在,请先注册");
        }

        if (thirdPartyLoginsVo.getCodeSwitch()) {
            // 短信验证
            String msg = redisTemplate.opsForValue().get(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
            if (StringUtils.isEmpty(msg)) {
                return R.fail("验证码已失效");
            }

            if (!thirdPartyLoginsVo.getPhoneMsg().equals(msg)) {
                return R.fail("短信验证码不正确");
            }
        } else {
            // 初始化加密工具
            // 验证：比对是否匹配
            boolean isOk = passwordEncoder.matches(thirdPartyLoginsVo.getPassWord(), tWxUser.getCPassword());
            /*if (!isOk) {
                return R.fail("密码错误");
            }*/
        }
        WxLoginUser wxUser = new WxLoginUser();
        BeanUtils.copyProperties(tWxUser, wxUser);
        // 生成并返回令牌
        String token = wxTokenService.createToken(wxUser);
        log.info("token的值：{}", token);
        if (token == null || token.isEmpty()) {
            return R.fail("生成令牌失败");
        }
        //给我把token的值保存到redis中
        redisTemplate.opsForValue().set(wxUser.getCOpenid(), token, 3, TimeUnit.DAYS);
        wxUser.setToken(token);
        // 返回用户信息
        // 记录登录信息
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(wxUser.getCOpenid(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        // 登录成功删除验证码
        redisTemplate.delete(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
        return R.ok(wxUser, "登录成功");
    }

    /**
     * 商户忘记密码接口
     *
     * @param thirdPartyLoginsVo
     * @return R<?>
     */
    @PostMapping("/resetPassword")
    @ApiOperation("商户忘记密码接口")
    public R<?> resetPassword(@RequestBody ThirdPartyLoginsVo thirdPartyLoginsVo) {
        // 核心正则表达式：
        // ^ 表示开头，$ 表示结尾
        // [a-zA-Z0-9] 表示只能是字母或数字
        // {8,20} 表示长度必须在8到20之间
        try {
            String regex = "^[a-zA-Z0-9]{8,20}$";
            boolean isMatch = Pattern.matches(regex, thirdPartyLoginsVo.getPassWord().trim());
            if (!isMatch) {
                // 根据需求返回指定的异常提示
                return R.fail("请输入8-20位数字/字母组合");
            }
            // 短信验证 sys:clientLogin:phone:手机号
            String msg = redisTemplate.opsForValue().get(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
            log.info("短信验证码的值：{}", msg);
            if (StringUtils.isEmpty(msg)) {
                return R.fail("验证码已失效");
            }
            if (msg != null && msg.startsWith("\"") && msg.endsWith("\"")) {
                msg = msg.substring(1, msg.length() - 1);
            }
            if (!thirdPartyLoginsVo.getPhoneMsg().equals(msg)) {
                return R.fail("短信验证码不正确");
            }
            // 重置密码逻辑
            LambdaUpdateWrapper<MaTechnician> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(MaTechnician::getTePhone, thirdPartyLoginsVo.getPhone());
            // 对密码进行加密
            String encryptedPassword = passwordEncoder.encode(thirdPartyLoginsVo.getPassWord());
            //updateWrapper.set(MaTechnician::getTePassword, encryptedPassword);
            maTechnicianService.update(updateWrapper);
            // 重置密码成功删除验证码
            redisTemplate.delete(PHONE_THREEUSERPARTCLIENT_CODE_KEY + thirdPartyLoginsVo.getPhone());
            return R.ok("重置密码成功");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 校验图形验证码接口
     *
     * @param req
     * @return R<?>
     */
    @PostMapping("/getValidateCaptcha")
    @ApiOperation("校验图形验证码接口")
    public R<?> getValidateCaptcha(@RequestBody ValidateCaptchaDto req) {
        try {
            log.info("校验图形验证码的请求参数：{}", JSON.toJSONString(req));
            validateCaptcha(req.getPhone(), req.getCode(), req.getUuid());
            return R.ok("校验成功");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 商户入驻申请接口
     *
     * @param req
     * @return R<?>
     */
    @PostMapping("/apply")
    @ApiOperation("商户入驻申请接口")
    public R<?> apply(@RequestBody MaTechnicianAppAddVo req) {
        try {
            // 1. 基础参数校验
            if (StringUtils.isAnyBlank(req.getTeName(), req.getTePhone(),  req.getAvatar())) {
                return R.fail("必填项不能为空");
            }
            //校验性别不能为空
            if (Objects.isNull(req.getTeSex())) {
                return R.fail("性别不能为空");
            }
            // 短信验证
            String msg = redisTemplate.opsForValue().get(PHONE_THREEUSERPARTCLIENT_CODE_KEY + req.getTePhone());
            log.info("短信验证码的值：{}", msg);
            /*if (StringUtils.isEmpty(msg)) {
                return R.fail("验证码已失效");
            }
            if (msg != null && msg.startsWith("\"") && msg.endsWith("\"")) {
                msg = msg.substring(1, msg.length() - 1);
            }
            if (!req.getPhoneMsg().equals(msg)) {
                return R.fail("短信验证码不正确");
            }*/
            if (StringUtils.isNotEmpty(req.getPhoneImgMsg())) {
                validateCaptcha(req.getTeName(), req.getPhoneImgMsg(), req.getUuid());
            }
            // 2. 调用业务层处理入驻申请
            maTechnicianService.apply(req);
            return R.ok("提交成功，进入审核流程");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code     验证码
     * @param uuid     唯一标识
     */
    public void validateCaptcha(String username, String code, String uuid) {
        boolean captchaEnabled = configService.selectCaptchaEnabled();
        if (captchaEnabled) {
            String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
            String captcha = redisCache.getCacheObject(verifyKey);
            redisCache.deleteObject(verifyKey);
            if (captcha == null) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
                throw new CaptchaExpireException();
            }
            if (!code.equalsIgnoreCase(captcha)) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
                throw new CaptchaException();
            }
        }
    }

    /**
     * 申请入驻
     *
     * @param req
     * @return R<?>
     */
    @PostMapping("/applyFile")
    @ApiOperation("申请入驻")
    public R<?> applyFile(@RequestBody MerchantApplyFileRequestDto req) {
        try {
            maTechnicianService.applyFile(req);
            return R.ok("申请入驻成功");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取待接单列表：前端传技师实时经纬度筛选订单
     */
    @PostMapping("/wait/list")
    @ApiOperation("获取待接单列表")
    public R<List<WaitOrderDTO>> getWaitOrder(@RequestBody WaitOrderQueryDTO query) {
        List<WaitOrderDTO> list = maTechnicianService.listWaitOrder(query);
        return R.ok(list);
    }

    /**
     * 滑动接单逻辑不变，
     * 仅列表查询逻辑修正
     */
    @PostMapping("/accept")
    @ApiOperation("滑动接单")
    public R<String> acceptOrder(@RequestBody AcceptOrderReqDTO req) {
        String tip = maTechnicianService.acceptOrder(req);
        return R.ok(tip);
    }

    /**
     * 技师接单确认逻辑不变，
     * 仅列表查询逻辑修正
     */
    @GetMapping("/rest/confirm")
    @ApiOperation("确认接单")
    public R<String> confirmRestAccept(@RequestParam Long techId, @RequestParam Long orderId) {
        String tip = maTechnicianService.confirmRestAccept(techId, orderId);
        return R.ok(tip);
    }

    /**
     * 技师拒绝接单逻辑不变，
     * 仅列表查询逻辑修正
     */
    @PostMapping("/refuse")
    @ApiOperation("拒绝接单")
    public R<String> refuseOrder(@RequestBody RefuseOrderReqDTO req) {
        maTechnicianService.refuseOrder(req);
        return R.ok("拒绝成功");
    }

    /**
     * 商户状态切换
     *
     * @param userId 商户ID
     * @param forceConfirm 是否强制切换 true:强制切换 false:不强制切换
     * @return R<?>
     */
    @GetMapping("/switchToOffline")
    @ApiOperation("商户状态切换")
    public R<?> switchToOffline(@RequestParam Long userId, @RequestParam Boolean forceConfirm) {
        try {
            return toR(maTechnicianService.switchToOffline(userId, forceConfirm));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询商户信息
     *
     * @param openid 微信openid
     * @return R<?>
     */
    @GetMapping("/getTechnician")
    @ApiOperation("查询商户信息")
    public R<?> getTechnician(@RequestParam String openid) {
        try {
            MerchantAuditFile technicianInfo = maTechnicianService.getTechnicianInfo(openid);
            return R.ok(technicianInfo.getMerchant());
        } catch (Exception e) {
            log.error("查询商户信息失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 查询商户信息和入驻资料
     *
     * @param openid 微信openid
     * @return R<?>
     */
    @GetMapping("/getTechnicianInfo")
    @ApiOperation("查询商户信息和入驻资料")
    public R<?> getTechnicianInfo(@RequestParam("openid") String openid) {
        try {
            return R.ok(maTechnicianService.getTechnicianInfo(openid));
        } catch (Exception e) {
            log.error("查询商户信息和入驻资料失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 修改商户信息
     *
     * @param req
     * @return R<?>
     */
    @PostMapping("/updateTechnician")
    @ApiOperation("修改商户信息")
    public R<?> updateTechnician(@Valid @RequestBody MerchantApplyFileRequestDto req) {
        try {
            maTechnicianService.updateTechnician(req);
            return R.ok("修改成功");
        } catch (Exception e) {
            log.error("修改商户信息失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 查询我的资料
     *
     * @param openid 微信openid
     * @return R<MerchantProfileVO>
     */
    @GetMapping("/profile")
    @ApiOperation("查询商户端我的资料")
    public R<MerchantProfileVO> getMerchantProfile(@RequestParam String openid) {
        try {
            return R.ok(maTechnicianService.getMerchantProfile(openid));
        } catch (Exception e) {
            log.error("查询商户端我的资料失败", e);
            return R.fail(e.getMessage());
        }
    }

    /**
     * 修改我的资料
     *
     * @param req
     * @return R<?>
     */
    @PostMapping("/profile/submit")
    @ApiOperation("提交商户端我的资料修改审核")
    public R<?> submitMerchantProfile(@Valid @RequestBody MerchantProfileSubmitDTO req) {
        try {
            maTechnicianService.submitMerchantProfile(req);
            return R.ok("提交成功，请等待审核");
        } catch (Exception e) {
            log.error("提交商户端我的资料修改审核失败", e);
            return R.fail(e.getMessage());
        }
    }

    @PreAuthorize("@ss.hasPermi('technician:technician:list')")
    @GetMapping("/list")
    public R<TableDataInfo> list(MaTechnician maTechnician) {
        startPage();
        List<MaTechnician> list = maTechnicianService.selectMaTechnicianList(maTechnician);
        return R.ok(getDataTable(list));
    }

    /**
     * 导出技师列表
     */
    @PreAuthorize("@ss.hasPermi('technician:technician:export')")
    @Log(title = "技师", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, MaTechnician maTechnician) {
        List<MaTechnician> list = maTechnicianService.selectMaTechnicianList(maTechnician);
        ExcelUtil<MaTechnician> util = new ExcelUtil<MaTechnician>(MaTechnician.class);
        util.exportExcel(response, list, "技师数据");
    }

    /**
     * 获取技师详细信息
     */
    @PreAuthorize("@ss.hasPermi('technician:technician:query')")
    @GetMapping(value = "/{id}")
    public R<MaTechnician> getInfo(@PathVariable("id") Long id) {
        return R.ok(maTechnicianService.selectMaTechnicianById(id));
    }

    /**
     * 新增技师
     */
    @ApiOperation("技师入驻")
    @PreAuthorize("@ss.hasPermi('technician:technician:add')")
    @Log(title = "技师", businessType = BusinessType.INSERT)
    @PostMapping
    public R<Void> add(@RequestBody MaTechnicianAppAddVo maTechnicianAppAddVo) {
        return toR(maTechnicianService.insertMaTechnician(maTechnicianAppAddVo));
    }

    /**
     * 后台新增商户
     *
     * @param dto 商户新增DTO
     * @return R<Void> 结果
     */
    @ApiOperation("后台新增商户")
    @PreAuthorize("@ss.hasPermi('technician:technician:add')")
    @Log(title = "商户", businessType = BusinessType.INSERT)
    @PostMapping("/merchant")
    public R<Void> addMerchant(@RequestBody MaTechnicianMerchantAddDTO dto) {
        try {
            LoginUser loginUser = getLoginUser();
            return toR(maTechnicianService.insertMerchant(dto, loginUser));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 后台编辑商户
     *
     * @param id  商户ID
     * @param dto 商户编辑DTO
     * @return R<Void> 结果
     */
    @ApiOperation("后台编辑商户")
    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
    @Log(title = "商户", businessType = BusinessType.UPDATE)
    @PutMapping("/merchant/{id}")
    public R<Void> editMerchant(@PathVariable("id") Integer id, @RequestBody MaTechnicianMerchantAddDTO dto) {
        try {
            LoginUser loginUser = getLoginUser();
            return toR(maTechnicianService.updateMerchant(id, dto, loginUser));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 后台变更商户管理状态
     *
     * @param id  商户ID
     * @param dto 状态变更参数
     * @return R<Void> 结果
     */
    @ApiOperation("后台变更商户管理状态")
    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
    @Log(title = "商户状态管理", businessType = BusinessType.UPDATE)
    @PutMapping("/merchant/{id}/status")
    public R<Void> changeMerchantStatus(@PathVariable("id") Integer id, @Valid @RequestBody MaTechnicianStatusChangeDTO dto) {
        try {
            LoginUser loginUser = getLoginUser();
            return toR(maTechnicianService.changeMerchantStatus(id, dto, loginUser));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 后台上传商户合同文件
     *
     * @param id  商户ID
     * @param map 合同文件
     * @return R 上传结果
     */
    @ApiOperation("后台上传商户合同文件")
    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
    @Log(title = "商户合同", businessType = BusinessType.UPDATE)
    @PostMapping("/merchant/{id}/contract")
    public R<Integer> uploadMerchantContract(@PathVariable("id") Integer id, @RequestBody Map<String, Object> map) {
        try {
            LoginUser loginUser = getLoginUser();
            return R.ok(maTechnicianService.uploadMerchantContract(id, map, loginUser));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询商户入驻审核列表
     *
     * @param page 分页参数
     * @param dto  查询条件
     * @return Page 商户入驻审核分页列表
     */
    @ApiOperation("后台查询商户入驻审核列表")
    @PreAuthorize("@ss.hasPermi('technician:technician:list')")
    @GetMapping("/merchant/audit/list")
    public R<Page<MaTechnicianAuditListVO>> merchantAuditList(Page<MaTechnicianAuditListVO> page, MaTechnicianAuditQueryDTO dto) {
        try {
            return R.ok(maTechnicianService.selectMerchantAuditList(page, dto));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 商户待入驻审核
     *
     * @param id  商户ID
     * @param dto 审核提交参数
     * @return R<Void> 结果
     */
    @ApiOperation("商户入驻审核")
    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
    @Log(title = "商户入驻审核", businessType = BusinessType.UPDATE)
    @PutMapping("/merchant/audit/{id}/submit")
    public R<Void> submitMerchantAudit(@PathVariable("id") Integer id, @RequestBody MaTechnicianAuditSubmitDTO dto) {
        try {
            LoginUser loginUser = getLoginUser();
            return toR(maTechnicianService.submitMerchantAudit(id, dto, loginUser));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }


    /**
     * 商户申请入驻审核
     *
     * @param id  商户ID
     * @param dto 审核提交参数
     * @return R<Void> 结果
     */
    @ApiOperation("商户申请入驻审核")
    @Log(title = "商户申请入驻审核", businessType = BusinessType.UPDATE)
    @PutMapping("/merchant/audit/{id}/applySubmit")
    public R<Void> applyMerchantAudit(@PathVariable("id") Integer id, @Valid @RequestBody MerchantProfileAuditDTO dto) {
        try {
            log.info("商户申请入驻申请请求参数：{}", JSON.toJSONString(dto));
            LoginUser loginUser = getLoginUser();
            return toR(maTechnicianService.auditMerchantProfile(id, dto, loginUser));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 待审核页面审核通过商户
     *
     * @param id  商户ID
     * @param dto 待审核通过参数
     * @return R<Void> 结果
     */
    @ApiOperation("待审核页面审核通过商户")
    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
    @Log(title = "商户待审核通过", businessType = BusinessType.UPDATE)
    @PutMapping("/merchant/audit/{id}/approve")
    public R<Void> approvePendingMerchantAudit(@PathVariable("id") Integer id, @RequestBody MaTechnicianPendingAuditSubmitDTO dto) {
        try {
            LoginUser loginUser = getLoginUser();
            return toR(maTechnicianService.approvePendingMerchantAudit(id, dto, loginUser));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询商户列表
     *
     * @param page 分页参数
     * @param dto  商户查询DTO
     * @return Page 商户分页列表
     */
    @ApiOperation("后台查询商户列表")
    @PreAuthorize("@ss.hasPermi('technician:technician:list')")
    @GetMapping("/merchant/list")
    public R<Page<MaTechnicianMerchantListVO>> merchantList
    (Page<MaTechnicianMerchantListVO> page, MaTechnicianMerchantQueryDTO dto) {
        try {
            return R.ok(maTechnicianService.selectMerchantList(page, dto));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询商户详情
     *
     * @param id 商户ID
     * @return R<MaTechnicianMerchantDetailVO> 商户详情
     */
    @ApiOperation("后台查询商户详情")
    @PreAuthorize("@ss.hasPermi('technician:technician:query')")
    @GetMapping("/merchant/detail/{id}")
    public R<MaTechnicianMerchantDetailVO> merchantDetail(@PathVariable("id") Long id) {
        try {
            return R.ok(maTechnicianService.selectMerchantDetail(id));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 查看商户证照
     *
     * @param id 商户ID
     * @return R<MaTechnicianCertificateVO> 商户证照
     */
    @ApiOperation("后台查看商户证照")
    @PreAuthorize("@ss.hasPermi('technician:technician:query')")
    @GetMapping("/merchant/{id}/certificate")
    public R<MaTechnicianCertificateVO> merchantCertificate(@PathVariable("id") Integer id) {
        try {
            return R.ok(maTechnicianService.selectMerchantCertificate(id));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 修改技师
     */
    @PreAuthorize("@ss.hasPermi('technician:technician:edit')")
    @Log(title = "技师", businessType = BusinessType.UPDATE)
    @PutMapping
    public R<Void> edit(@RequestBody MaTechnicianAppAddVo maTechnicianAppAddVo) {
        return toR(maTechnicianService.updateMaTechnician(maTechnicianAppAddVo));
    }

    /**
     * 删除技师
     */
    @PreAuthorize("@ss.hasPermi('technician:technician:remove')")
    @Log(title = "技师", businessType = BusinessType.DELETE)
    @DeleteMapping("/{ids}")
    public R<Void> remove(@PathVariable Long[] ids) {
        return toR(maTechnicianService.deleteMaTechnicianByIds(ids));
    }

    /**
     * 获取服务类目列表
     *
     * @return List<ServiceCategory> 服务类目列表
     */
    @GetMapping("/getServiceCategoryList")
    @ApiOperation("获取服务类目列表")
    public R<List<ServiceCategory>> getServiceCategoryList() {
        try {
            List<ServiceCategory> list = serviceCategoryService.listH5ServiceCategory();
            return R.ok(list);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 获取商户的技能列表
     *
     * @param req
     * @return R<List<MaProject>>
     */
    @PostMapping("/getSkillList")
    @ApiOperation("获取商户的技能列表")
    public R<List<MaProject>> getSkillList(@RequestBody MaProjectGetVo req) {
        try {
            List<MaProject> list = maTechnicianService.selectMaTechnicianListBy(req.getMerchantId(), req.getAuditStatus());
            return R.ok(list);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 查询未开通的服务项目列表
     *
     * @param req
     * @return R<?>
     */
    @PostMapping("/getNotApplyList")
    @ApiOperation("查询未开通的服务项目列表")
    public R<?> getNotApplyList(@RequestBody MaProjectGetVo req) {
        try {
            return R.ok(maTechnicianService.getNotApplyList(req.getMerchantId(), req.getServiceTag()));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 申请开通新服务
     *
     * @param dto
     * @return R<Void>
     */
    @PostMapping("/applyForService")
    @ApiOperation("申请开通新服务")
    public R<Void> applyForService(@RequestBody MaProjectSaveDto dto) {
        try {
            return toR(maTechnicianService.applyForService(dto));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 重新申请开通新服务
     *
     * @param req
     * @return R<?>
     */
    @PostMapping("/updateApply")
    @ApiOperation("重新申请开通新服务")
    public R<?> updateApply(@RequestBody MaProjectUpdateDto req) {
        try {
            if (req.getProjectId() != null && StringUtils.isNotBlank(req.getApplyReason())) {
                LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(MaProject::getProjectId, req.getProjectId());
                updateWrapper.set(MaProject::getApplyReason, req.getApplyReason());
                updateWrapper.set(MaProject::getAuditStatus, 0);
                // 更新申请时间
                updateWrapper.set(MaProject::getApplyTime, new Date());
                maProjectService.update(updateWrapper);
            }
            return R.ok("重新申请成功,提交到审核阶段");
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    /**
     * 申请下架,删除服务项目,编辑售价价格
     *
     * @param req
     * @return R<?>
     */
    @PostMapping("/updateMaProject")
    @ApiOperation("申请下架,删除服务项目,编辑售价价格")
    public R<?> updateMaProject(@RequestBody MaProjectUpdateDto req) {
        String message = "";
        if (req.getProjectId() != null) {
            // 删除项目
            if (req.getIsDelete() != null && req.getIsDelete() == true) {
                LambdaQueryWrapper<MaProject> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(MaProject::getProjectId, req.getProjectId());
                maProjectService.remove(queryWrapper);
                message = "删除成功";
                return R.ok(message);
            }
            // 下架项目
            if (req.getIsPass() != null && req.getIsPass() == true) {
                //判断当前项目是否已开通
                LambdaQueryWrapper<MaProject> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(MaProject::getProjectId, req.getProjectId());
                queryWrapper.eq(MaProject::getAuditStatus, 1);
                MaProject one = maProjectService.getOne(queryWrapper);
                if (one == null) {
                    return R.fail("项目未开通,不能下架");
                }
                LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(MaProject::getId, req.getProjectId());
                updateWrapper.set(MaProject::getProjectIsEnable, 1);
                maProjectService.update(updateWrapper);
                message = "申请下架成功";
                return R.ok(message);
            }
            // 修改价格
            if (req.getProjectCurrentPrice() != null) {
                //判断当前项目是否已开通
                LambdaQueryWrapper<MaProject> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(MaProject::getProjectId, req.getProjectId());
                queryWrapper.eq(MaProject::getAuditStatus, 1);
                MaProject one = maProjectService.getOne(queryWrapper);
                if (one == null) {
                    return R.fail("项目未开通,不能修改价格");
                }
                LambdaUpdateWrapper<MaProject> updateWrapper = new LambdaUpdateWrapper<>();
                updateWrapper.eq(MaProject::getId, req.getProjectId());
                updateWrapper.set(MaProject::getProjectCurrentPrice, req.getProjectCurrentPrice());
                maProjectService.update(updateWrapper);
                message = "修改价格完成";
                return R.ok(message);
            }
        }
        return R.fail("项目ID不能为空");
    }

    /**
     * 商户入驻信息
     *
     * @param userId
     * @return R<?>
     */
    @GetMapping("/getTechnicianList")
    @ApiOperation("商户入驻信息")
    public R<?> getTechnicianList(@RequestParam(value = "userId") Integer userId) {
        return R.ok(maTechnicianService.getTechnicianList(userId));
    }

    /**
     * 查询商户合同记录信息
     *
     * @param userId
     * @return R<ContractRecordVO>
     */
    @GetMapping("/getContractRecords")
    @ApiOperation("查询商户合同记录信息")
    public R<ContractRecordVO> getContractRecords(@RequestParam(value = "userId") Long userId) {
        try {
            return R.ok(maTechnicianService.getContractRecords(userId));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }

    private R<Void> toR(int rows) {
        return rows > 0 ? R.ok() : R.fail();
    }

    private R<?> toR(Result<?> result) {
        if (result == null) {
            return R.fail();
        }
        return result.isSuccess() ? R.ok(result.getResult(), result.getMessage()) : R.fail(result.getResult(), result.getMessage());
    }

}
