package org.dromara.zjk.controller;

import cn.dev33.satoken.annotation.SaCheckRole;
import cn.dev33.satoken.annotation.SaMode;
import cn.hutool.core.collection.CollUtil;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.validate.AddGroup;
import org.dromara.common.core.validate.EditGroup;

import org.dromara.common.excel.utils.ExcelUtil;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
import org.dromara.common.log.enums.OperatorType;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.zjk.domain.ExpertBaseInfo;
import org.dromara.zjk.domain.bo.ApprovalCommonBo;
import org.dromara.zjk.domain.bo.ZjkExpertBo;
import org.dromara.zjk.domain.vo.ExpertPerformWorkCountVO;
import org.dromara.zjk.domain.vo.ZjkExpertVo;
import org.dromara.zjk.enums.ResultTypeEnum;
import org.dromara.zjk.enums.ZjkExpertTypeEnum;
import org.dromara.zjk.service.IZjkExpertService;
import org.dromara.zjk.zwy.annotation.DecryptOperation;
import org.dromara.zjk.zwy.annotation.EncryptOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 专家库
 * 前端访问路由地址为:/expert/expert
 *
 * @author wangtong
 * @date 2024-10-24
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/expert")
public class ZjkExpertController extends BaseController {

    private final IZjkExpertService zjkExpertService;


    /**
     * 查询专家库列表信息
     * @param bo
     * @param pageQuery
     * @return
     */
    @DecryptOperation
    @GetMapping("/expertList")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public TableDataInfo<ZjkExpertVo> expertList(ZjkExpertBo bo, PageQuery pageQuery) {
        bo.setStatus(ZjkExpertTypeEnum.NORMAL.getCode());
        return zjkExpertService.expertList(bo, pageQuery);
    }


    /**
     * 待审批专家列表
     * @param bo
     * @param pageQuery
     * @return
     */
    @DecryptOperation
    @GetMapping("/pendingApproval")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY
    }, mode = SaMode.OR)
    public TableDataInfo<ZjkExpertVo> pendingApproval(ZjkExpertBo bo, PageQuery pageQuery) {
        bo.setStatus(ZjkExpertTypeEnum.APPROVAL.getCode());
        return zjkExpertService.expertList(bo, pageQuery);
    }




    /**
     * 查询专家审批列表信息
     * @param bo
     * @param pageQuery
     * @return
     */
    @DecryptOperation
    @GetMapping("/list")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public TableDataInfo<ZjkExpertVo> list(ZjkExpertBo bo, PageQuery pageQuery) {
        return zjkExpertService.expertInquiry(bo, pageQuery);
    }



    /**
     * 专家查询列表信息
     * @param bo
     * @param pageQuery
     * @return
     */
    @DecryptOperation
    @GetMapping("/expertInquiry")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY,
        TenantConstants.XM_ROLE_KEY
    }, mode = SaMode.OR)
    public TableDataInfo<ZjkExpertVo>  expertInquiry(ZjkExpertBo bo, PageQuery pageQuery) {
        bo.setStatus(ZjkExpertTypeEnum.NORMAL.getCode());
        return zjkExpertService.expertInquiry(bo, pageQuery);
    }


    /**
     * 查询全部在库专家列表
     */
    @DecryptOperation
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    @GetMapping("/querylist")
    public TableDataInfo<ZjkExpertVo> querylist() {
        return zjkExpertService.querylist();
    }

    /**
     * 专家信息导出
     * @param bo
     * @param response
     */
    @DecryptOperation
    @Log(title = "专家库-专家信息导出", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public void export(@ModelAttribute ZjkExpertBo bo, HttpServletResponse response) {
        if (bo.getIsTemplate() == 0){
            List<ZjkExpertVo> list = new ArrayList<>();
            ExcelUtil.exportExcel(list, "专家库模板", ZjkExpertVo.class, response);
        }else {
            List<ZjkExpertVo> list = zjkExpertService.exportList(bo);
            ExcelUtil.exportExcel(list, "专家库", ZjkExpertVo.class, response);
        }
    }

    /**
     * 专家信息导入
     * @param file
     * @return
     */
    @EncryptOperation
    @Log(title = "专家库-专家信息导入", businessType = BusinessType.IMPORT)
    @PostMapping("/imports")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public R<Void> imports(@RequestPart("file") MultipartFile file) {
        List<String> list = zjkExpertService.imports(file);
        // 如果存在重复的身份证号则提示，剔除之后再次导入
        if (!CollUtil.isEmpty(list)){
            // 将身份证号列表转换为用逗号分隔的字符串
            return R.fail("以下身份证号专家已经存在，请剔除后再次导入专家数据：" + String.join(", ", list));
        }
        return R.ok();
    }

    /**
     * 获取专家信息详情
     * @param id
     * @return
     */
    @DecryptOperation
    @Log(title = "专家库-专家个人资料", businessType = BusinessType.VIEW)
    @GetMapping("/{id}")
    public R<ZjkExpertVo> getInfo(@NotNull(message = "主键不能为空")
                                     @PathVariable Long id) {
        return R.ok(zjkExpertService.queryById(id));
    }

    /**
     * 专家信息暂存 申请
     * @param bo
     * @return
     */
    @EncryptOperation
    @Log(title = "专家库-专家信息暂存/提交", businessType = BusinessType.EXPERT_SYS,operatorType = OperatorType.BROWSER)
    @RepeatSubmit()
    @PostMapping("save")
    @SaCheckRole(value = {
        TenantConstants.EXPERT_ROLE_KEY,
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public R<Void> save(@Validated(AddGroup.class) @RequestBody ZjkExpertBo bo) {
        return toAjax(zjkExpertService.insertByBo(bo));
    }

    /**
     * 提交
     */
    @EncryptOperation
    @Log(title = "专家入库提交", businessType = BusinessType.EXPERT_SYS,operatorType = OperatorType.BROWSER)
    @RepeatSubmit()
    @PostMapping("sub")
    public R<Void> sub(@Validated(AddGroup.class) @RequestBody ZjkExpertBo bo) {
        bo.setStatus(ZjkExpertTypeEnum.APPROVAL.getCode());
        return toAjax(zjkExpertService.insertByBo(bo));
    }


    /**
     * 审批操作
     * @param approvalCommonBo
     * @return
     */
    @Log(title = "专家库-专家信息审批", businessType = BusinessType.APPROVE)
    @RepeatSubmit()
    @PostMapping("approval")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public R<Void> approval(@Validated(AddGroup.class) @RequestBody ApprovalCommonBo approvalCommonBo) {
        if (approvalCommonBo.getApprovalStatus()==null||approvalCommonBo.getId()==null){
            return R.fail("参数不正确");
        }else if (approvalCommonBo.getApprovalStatus()==0&& StringUtils.isEmpty(approvalCommonBo.getReason())){
                return R.fail("驳回理由不能为空");
        }
        ZjkExpertBo expert = new ZjkExpertBo();
        expert.setExpertId(approvalCommonBo.getId());
        expert.setRemark(approvalCommonBo.getReason());
        expert.setStatus(approvalCommonBo.getApprovalStatus()== ResultTypeEnum.SUCCESS.getCode()? ZjkExpertTypeEnum.NORMAL.getCode(): ZjkExpertTypeEnum.REFUSE.getCode());
        return toAjax(zjkExpertService.approval(expert));
    }

    /**
     * 修改expert/停用/启用
     */
    @EncryptOperation
    @Log(title = "专家库-专家信息修改", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PostMapping("/update")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody ZjkExpertBo bo) {
        return toAjax(zjkExpertService.updateByBo(bo));
    }

    /**
     * 删除expert
     * @param ids 主键串
     */
    @Log(title = "专家库-专家信息删除", businessType = BusinessType.DELETE)
    @GetMapping("delete/{ids}")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable Long[] ids) {
        return toAjax(zjkExpertService.deleteWithValidByIds(List.of(ids), true));
    }

    /**
     * 根据用户 id 获取专家详细信息
     * @return
     */
    @DecryptOperation
    @Log(title = "专家库-专家信息", businessType = BusinessType.VIEW)
    @GetMapping("/getUserInfo")
    @SaCheckRole(value = {
        TenantConstants.EXPERT_ROLE_KEY,
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public R<ZjkExpertVo> getInfoByUserId() {
        return R.ok(zjkExpertService.queryByUserId(LoginHelper.getUserId(),null));
    }



    /**
     * 根据用户 id 获取专家详细信息
     * @return
     */
    @DecryptOperation
    @Log(title = "专家库-专家信息", businessType = BusinessType.VIEW)
    @PostMapping("/getExpertInfo")
    @SaCheckRole(value = {
        TenantConstants.EXPERT_ROLE_KEY,
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    }, mode = SaMode.OR)
    public R<ZjkExpertVo> getInfoByUserIdAndExpertId(@RequestBody ZjkExpertBo bo) {
        return R.ok(zjkExpertService.queryByUserId(bo.getUserId(),bo.getExpertId()));
    }


    /**
     * 撤销申请
     * @return
     */
    @Log(title = "专家库-专家信息", businessType = BusinessType.QUASH)
    @SaCheckRole(value = TenantConstants.EXPERT_ROLE_KEY)
    @GetMapping("/expertQuash")
    public R<Void> expertQuash() {
        return toAjax(zjkExpertService.expertQuash(1,null));
    }


    /**
     * 获取专家总数
     * @return
     */
    @SaCheckRole(value={
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY,
        TenantConstants.XM_ROLE_KEY,
        TenantConstants.EXPERT_ROLE_KEY,
    },mode = SaMode.OR)
    @GetMapping("/getExpertCount")
    public R<Long> getExpertCount() {
        return R.ok("success",zjkExpertService.getExpertCount());
    }

    /**
     * 获取专家基本信息
     * @return
     */
    @DecryptOperation
    @Log(title = "获取专家基本信息", businessType = BusinessType.VIEW)
    @GetMapping("/getExpertBaseInfo")
    @SaCheckRole(value = {
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY,
        TenantConstants.EXPERT_ROLE_KEY
    }, mode = SaMode.OR)
    public R<ExpertBaseInfo> getExpertBaseInfo() {
        return R.ok(zjkExpertService.getExpertBaseInfo());
    }


    /**
     * 专家各领域人数
     * @return
     */
    @SaCheckRole(value={
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    },mode = SaMode.OR)
    @GetMapping("getExpertPerformWorkCount")
    public R<List<ExpertPerformWorkCountVO>> getExpertPerformWorkCount(@RequestParam(name = "days",required = false)Integer days) {
        return R.ok(zjkExpertService.getExpertPerformWorkCount(days));
    }

    /**
     * 专家单位类型统计
     * @return
     */
    @SaCheckRole(value={
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    },mode = SaMode.OR)
    @GetMapping("getUnitCount")
    public R<List<ExpertPerformWorkCountVO>> getUnitCount() {
        return R.ok(zjkExpertService.getUnitCount());
    }

    /**
     * 专家政治面貌统计
     * @return
     */
    @SaCheckRole(value={
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    },mode = SaMode.OR)
    @GetMapping("getPoliticsCount")
    public R<List<ExpertPerformWorkCountVO>> getPoliticsCount() {
        return R.ok(zjkExpertService.getPoliticsCount());
    }

    /**
     * 专家各个年龄区间段的人数
     * @return
     */
    @SaCheckRole(value={
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    },mode = SaMode.OR)
    @GetMapping("getAgeRangeStatistics")
    public R<List<Map<String, Integer>>> getAgeRangeStatistics() {
        return R.ok(zjkExpertService.getAgeRangeStatistics());
    }


    /**
     * 专家工作年限
     * @return
     */
    @SaCheckRole(value={
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY,
        TenantConstants.EXPERT_ROLE_KEY,
    },mode = SaMode.OR)
    @GetMapping("/workProfessialYear")
    public R<List<Map<String, Integer>>> workProfessialYear() {
        return R.ok(zjkExpertService.workProfessialYear());
    }


    /**
     * 专家入库时间分析
     * @return
     */
    @SaCheckRole(value={
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    },mode = SaMode.OR)
    @GetMapping("getApprovalTimeAnalysis")
    public R<List<Map<String, Integer>>> getApprovalTimeAnalysis(@RequestParam(name = "startTime",required = false)String startTime,@RequestParam(name = "endTime",required = false)String endTime) {
        return R.ok(zjkExpertService.getApprovalTimeAnalysis(startTime,endTime));
    }

    /**
     * 当前年入库专家总数
     * @return
     */
    @SaCheckRole(value={
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    },mode = SaMode.OR)
    @GetMapping("/approval-time-count")
    public R<Long> getApprovalTimeCountThisYear() {
        return R.ok("success",zjkExpertService.getApprovalTimeCountThisYear());
    }

    /**
     * 远程调用获取专家信息
     * @return
     */
    @DecryptOperation
    @SaCheckRole(value={
        TenantConstants.EXPERT_ROLE_KEY,
        TenantConstants.JG_ROLE_KEY,
        TenantConstants.SUPER_ADMIN_ROLE_KEY,
        TenantConstants.TENANT_ADMIN_ROLE_KEY
    },mode = SaMode.OR)
    @GetMapping("/api/fetchRemoteProfessors")
    public R<Void> fetchRemoteProfessors() {
        zjkExpertService.fetchRemoteProfessors();
        return R.ok();
    }


}
