package com.fs.doctor.service.impl;

import cn.hutool.core.util.IdUtil;
import com.fs.audit.chain.AuditResult;
import com.fs.audit.domain.AuditFlow;
import com.fs.audit.dto.AuditRequestDTO;
import com.fs.audit.dto.CreateAuditRequestDTO;
import com.fs.audit.enums.AuditStatus;
import com.fs.audit.enums.AuditTypeEnum;
import com.fs.audit.enums.AuditUserType;
import com.fs.audit.exception.BusinessException;
import com.fs.audit.mapper.AuditFlowMapper;
import com.fs.audit.service.AuditService;
import com.fs.audit.utils.AuditFlowUtils;
import com.fs.common.BeanCopyUtils;
import com.fs.common.config.LoginContextManager;
import com.fs.common.core.domain.entity.SysUser;
import com.fs.common.core.domain.model.LoginUser;
import com.fs.common.enums.UserTypeEnum;
import com.fs.common.utils.DateUtils;
import com.fs.common.utils.SecurityUtils;
import com.fs.common.utils.StringUtils;
import com.fs.company.domain.CompanyUser;
import com.fs.company.service.ICompanyUserService;
import com.fs.doctor.domain.Doctor;
import com.fs.doctor.enums.DoctorAuditStatus;
import com.fs.doctor.mapper.DoctorMapper;
import com.fs.doctor.service.IDoctorService;
import com.fs.doctor.vo.*;
import com.fs.system.service.ISysUserService;
import com.fs.task.vo.audit_Info.AuditFlowVO;
import org.apache.ibatis.annotations.Param;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * 讲者主Service业务层处理
 *
 * @author fs
 * @date 2025-12-30
 */
@Service
public class DoctorServiceImpl implements IDoctorService {
    @Autowired
    private DoctorMapper doctorMapper;
    @Lazy
    @Autowired
    private AuditService auditService;
    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ICompanyUserService companyUserService;

    /**
     * 查询讲者主
     *
     * @param id 讲者主主键
     * @return 讲者主
     */
    @Override
    public Doctor selectDoctorById(Long id) {
        return doctorMapper.selectDoctorById(id);
    }

    /**
     * 查询讲者主列表
     *
     * @param doctor 讲者主
     * @return 讲者主
     */
    @Override
    public List<Doctor> selectDoctorList(Doctor doctor) {
        return doctorMapper.selectDoctorList(doctor);
    }

    /**
     * 新增讲者主
     *
     * @param doctor 讲者主
     * @return 结果
     */
    @Override
    public int insertDoctor(Doctor doctor) {
        doctor.setCreateTime(DateUtils.getNowDate());
        return doctorMapper.insertDoctor(doctor);
    }

    /**
     * 修改讲者主
     *
     * @param doctor 讲者主
     * @return 结果
     */
    @Override
    public int updateDoctor(Doctor doctor) {
        doctor.setUpdateTime(DateUtils.getNowDate());
        return doctorMapper.updateDoctor(doctor);
    }

    /**
     * 批量删除讲者主
     *
     * @param ids 需要删除的讲者主主键
     * @return 结果
     */
    @Override
    public int deleteDoctorByIds(Long[] ids) {
        return doctorMapper.deleteDoctorByIds(ids);
    }

    /**
     * 删除讲者主信息
     *
     * @param id 讲者主主键
     * @return 结果
     */
    @Override
    public int deleteDoctorById(Long id) {
        return doctorMapper.deleteDoctorById(id);
    }


    @Override
    public List<DoctorOptionRespVO> getDoctorOptionVOList(DoctorOptionReqVO doctorOptionReqVO) {
        return doctorMapper.getDoctorOptionVOList(doctorOptionReqVO);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int add(DoctorVO doctorVO) {
        Doctor doctor = BeanCopyUtils.copy(doctorVO, Doctor.class);

        String mobile = doctor.getMobile();
        if(mobile.isEmpty()){
            throw new RuntimeException("电话号码不能为空");
        }
        int exists = doctorMapper.countByMobile(mobile);
        if(exists!=0){
            throw new RuntimeException("电话号码已有讲者使用");

        }


        // doctor_id NOT NULL：必须先生成
        doctor.setDoctorId("CD" +  IdUtil.getSnowflake(1L, 1L).nextId());

        // 状态：后端强制待审核
        doctor.setStatus(DoctorAuditStatus.PENDING.getCode().longValue());
        //密码加密
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        doctor.setPwd(encoder.encode(doctor.getPwd()));
        int insertCount = doctorMapper.insertDoctor(doctor);
        if (insertCount != 1 || doctor.getId() == null) {
            throw new RuntimeException("新增Doctor失败");
        }

        LoginUser loginUser = SecurityUtils.getLoginUser();
        if (loginUser == null) {
            throw new RuntimeException("未登录，无法发起Doctor审核");
        }

        CreateAuditRequestDTO dto = new CreateAuditRequestDTO();
        dto.setBusinessId(doctor.getId());
        dto.setBusinessType(AuditTypeEnum.DOCTOR_AUDIT.getCode());
        dto.setTempCode(AuditTypeEnum.DOCTOR_AUDIT.getCode());
        dto.setInitiatorId(loginUser.getUserId());
        dto.setCompanyId(doctor.getCompanyId());

        Long auditId = auditService.createAudit(dto);
        if (auditId == null) {
            throw new RuntimeException("创建审核实例失败：auditId为空");
        }

        int upd = doctorMapper.updateAuditInstanceIdById(doctor.getId(), auditId);
        if (upd != 1) {
            throw new RuntimeException("回写auditInstanceId失败");
        }

        return insertCount;
    }

    @Transactional
    @Override
    public int addByCompany(DoctorVO doctorVO) {
        Doctor doctor = BeanCopyUtils.copy(doctorVO, Doctor.class);


        String mobile = doctor.getMobile();
        if(mobile.isEmpty()){
            throw new RuntimeException("电话号码不能为空");
        }
        int exists = doctorMapper.countByMobile(mobile);
        if(exists!=0){
            throw new RuntimeException("电话号码已有讲者使用");

        }


        // doctor_id NOT NULL：必须先生成
        doctor.setDoctorId("CD" + IdUtil.getSnowflake(1L, 1L).nextId());

        // 状态：后端强制待审核
        doctor.setStatus(DoctorAuditStatus.PENDING.getCode().longValue());
        //密码加密
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        doctor.setPwd(encoder.encode(doctor.getPwd()));
        int insertCount = doctorMapper.insertDoctor(doctor);
        if (insertCount != 1 || doctor.getId() == null) {
            throw new RuntimeException("新增Doctor失败");
        }

        Long currentCompanyUserId = LoginContextManager.getCurrentCompanyUserId();
        if (currentCompanyUserId == null) {
            throw new RuntimeException("未登录，无法发起Doctor审核");
        }

        CreateAuditRequestDTO dto = new CreateAuditRequestDTO();
        dto.setBusinessId(doctor.getId());
        dto.setBusinessType(AuditTypeEnum.DOCTOR_AUDIT.getCode());
        dto.setTempCode(AuditTypeEnum.DOCTOR_AUDIT.getCode());
        dto.setInitiatorId(currentCompanyUserId);
        dto.setCompanyId(doctor.getCompanyId());

        Long auditId = auditService.createAudit(dto);
        if (auditId == null) {
            throw new RuntimeException("创建审核实例失败：auditId为空");
        }

        int upd = doctorMapper.updateAuditInstanceIdById(doctor.getId(), auditId);
        if (upd != 1) {
            throw new RuntimeException("回写auditInstanceId失败");
        }

        return insertCount;
    }

    @Override
    public DoctorAuditVO  selectDoctorAuditInfo(Long id) {
        DoctorAuditVO doctorAuditVO = new DoctorAuditVO();
        Doctor doctor = this.selectDoctorById(id);
        DoctorVO doctorVO = BeanCopyUtils.copy(doctor, DoctorVO.class);
        Long auditInstanceId = doctorVO.getAuditInstanceId();

        // 获取审核流程
        List<AuditFlow> auditFlows = auditService.getAuditFlows(auditInstanceId);
        List<AuditFlowVO> auditFlowVOS = BeanCopyUtils.copyList(auditFlows, AuditFlowVO.class);
        for (AuditFlowVO auditFlowVO : auditFlowVOS) {

            // 1) 审核状态中文
            auditFlowVO.setStatusName(AuditStatus.fromCode(auditFlowVO.getStatus()).getDesc());

            // 2) step=0（申请人）特殊处理：审核时间使用创建时间
            boolean isStep0 = auditFlowVO.getStepNumber() != null && auditFlowVO.getStepNumber() == 0;
            if (isStep0 && auditFlowVO.getAuditTime() == null) {
                auditFlowVO.setAuditTime(auditFlowVO.getCreateTime());
            }

            // 3) 统一算出"要展示的审核人ID"
            //    优先 auditUserId，其次从 auditUserIds 取第一个
            Long displayUserId = auditFlowVO.getAuditUserId();
            if (displayUserId == null) {
                displayUserId = AuditFlowUtils.parseFirstIdFromAuditUserIds(auditFlowVO.getAuditUserIds());
            }

            if (displayUserId == null) {
                auditFlowVO.setAuditUserName("-");
                continue;
            }

            // 4) 统一算出"审核人类型"
            //    VO 约定：0 销售(company_user) / 1 系统用户(sys_user)
            Integer typeCode = auditFlowVO.getAuditUserType();

            // ✅ 如果类型为空：走兜底双查（先 company_user 再 sys_user）
            if (typeCode == null) {
                // 类型缺失，走兜底双查（下面会处理）
                typeCode = -1;
            }

            // 5) 根据类型查用户名
            String name = "-";

            if (typeCode == 1) {
                // 系统用户
                SysUser sysUser = sysUserService.selectUserById(displayUserId);
                if (sysUser != null) name = sysUser.getUserName();

            } else if (typeCode == 0) {
                // 销售/公司用户
                CompanyUser cu = companyUserService.selectCompanyUserById(displayUserId);
                if (cu != null) name = cu.getUserName();

            } else {
                // typeCode == -1：兜底双查（先 company_user 后 sys_user）
                CompanyUser cu = companyUserService.selectCompanyUserById(displayUserId);
                if (cu != null) {
                    name = cu.getUserName();
                    // 顺便把类型补回去（可选）
                    auditFlowVO.setAuditUserType(0);
                } else {
                    SysUser sysUser = sysUserService.selectUserById(displayUserId);
                    if (sysUser != null) {
                        name = sysUser.getUserName();
                        auditFlowVO.setAuditUserType(1);
                    }
                }
            }

            auditFlowVO.setAuditUserName(name);
        }

        doctorAuditVO.setDoctorVO(doctorVO);
        doctorAuditVO.setAuditFlowVOList(auditFlowVOS);


        return doctorAuditVO;
    }

    @Override
    public void doAudit(DoctorDoAuditReqVO doctorDoAuditReqVO) {
        // 从安全上下文拿当前登录人
        Long userId = LoginContextManager.getCurrentCompanyUserId();
        if (Objects.isNull(userId)) {
            throw new BusinessException("当前用户不存在");
        }
        Long doctorId = doctorDoAuditReqVO.getId();
        if (Objects.isNull(doctorId)) {
            throw new BusinessException("医生id不能为空");
        }



        Doctor doctor = this.selectDoctorById(doctorId);
        if (Objects.isNull(doctor)) {
            throw new BusinessException("审核的医生信息不存在");
        }
        // contract_status：0未签约 1已签约
        if (doctor.getContractStatus() == null || doctor.getContractStatus() == 0) {
            throw new BusinessException("该医生未签约，不能审核通过");
        }


        Long auditInstanceId = doctor.getAuditInstanceId();

        //调用审核执行
        AuditRequestDTO auditRequestDTO = new AuditRequestDTO();
        auditRequestDTO.setAuditId(auditInstanceId);
        auditRequestDTO.setUserId(userId);
        auditRequestDTO.setUserType(UserTypeEnum.SALES.getCode());
        auditRequestDTO.setComment(doctorDoAuditReqVO.getAuditOpinion());
        auditRequestDTO.setCompanyId(doctorDoAuditReqVO.getCompanyId());
        auditRequestDTO.setAction(doctorDoAuditReqVO.getAuditStatus());
        auditService.doAudit(auditRequestDTO);

        //回填医生信息表
        doctor.setStatus(doctorDoAuditReqVO.getAuditStatus().longValue());

        this.updateDoctor(doctor);

    }


    @Override
    public void appDoAudit(DoctorDoAuditReqVO doctorDoAuditReqVO) {
        // 从安全上下文拿当前登录人
        Long userId =doctorDoAuditReqVO.getAuditUserId();
        if (Objects.isNull(userId)) {
            throw new BusinessException("当前用户不存在");
        }
        Long doctorId = doctorDoAuditReqVO.getId();
        if (Objects.isNull(doctorId)) {
            throw new BusinessException("医生id不能为空");
        }



        Doctor doctor = this.selectDoctorById(doctorId);
        if (Objects.isNull(doctor)) {
            throw new BusinessException("审核的医生信息不存在");
        }
        // contract_status：0未签约 1已签约
        if (doctor.getContractStatus() == null || doctor.getContractStatus() == 0) {
            throw new BusinessException("该医生未签约，不能审核通过");
        }


        Long auditInstanceId = doctor.getAuditInstanceId();

        //调用审核执行
        AuditRequestDTO auditRequestDTO = new AuditRequestDTO();
        auditRequestDTO.setAuditId(auditInstanceId);
        auditRequestDTO.setUserId(userId);
        auditRequestDTO.setUserType(UserTypeEnum.SALES.getCode());
        auditRequestDTO.setComment(doctorDoAuditReqVO.getAuditOpinion());
        auditRequestDTO.setCompanyId(doctorDoAuditReqVO.getCompanyId());
        auditRequestDTO.setAction(doctorDoAuditReqVO.getAuditStatus());
        AuditResult auditResult = auditService.doAudit(auditRequestDTO);
        if(!auditResult.isSuccess()){
            throw new BusinessException(auditResult.getMessage());
        }

        //回填医生信息表
        doctor.setStatus(doctorDoAuditReqVO.getAuditStatus().longValue());

        this.updateDoctor(doctor);

    }

    @Override
    public int resetPwd(DoctorResetPwdReqVO req) {
        if (req == null || req.getId() == null) {
            throw new RuntimeException("id不能为空");
        }
        if (StringUtils.isEmpty(req.getNewPwd())) {
            throw new RuntimeException("新密码不能为空");
        }

        // 这里可加密码强度校验：长度、复杂度等
        if (req.getNewPwd().length() < 6 || req.getNewPwd().length() > 20) {
            throw new RuntimeException("密码长度需在6-20位");
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPwd = encoder.encode(req.getNewPwd());

        // 只更新 pwd
        Doctor update = new Doctor();
        update.setId(req.getId());
        update.setPwd(encodedPwd);

        return doctorMapper.updateDoctorPwd(update); // 建议单独 mapper 方法，只更新 pwd
    }


    @Override
    public Doctor selectDoctorByDoctorId(String doctorId) {
        return doctorMapper.selectDoctorByDoctorId(doctorId);
    }

    @Override
    public void addPoints(Long doctorId, BigDecimal points) {
        doctorMapper.addPoints(doctorId,points);
    }

    @Override
    public void resetPassword(Doctor doctor) {
        doctorMapper.updateDoctor(doctor);
    }

    @Override
    public Doctor selectDoctorByPhone(String phone) {

        return doctorMapper.selectDoctorByPhone(phone);
    }


}
