package org.dromara.business.controller;

import cn.dev33.satoken.annotation.SaIgnore;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.opencsv.CSVReader;
import com.opencsv.CSVReaderBuilder;
import com.opencsv.CSVWriter;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.dromara.business.domain.bo.CaseImportUserBo;
import org.dromara.business.domain.vo.CaseExcelImportUserVo;
import org.dromara.business.domain.vo.CaseImportUserVo;
import org.dromara.business.listener.CaseUserImportListener;
import org.dromara.business.service.ICaseImportUserService;
import org.dromara.common.core.constant.UserConstants;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.ServiceException;
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.core.ExcelResult;
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.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.system.domain.bo.SysUserBo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysUserService;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 用户导入记录
 *
 * @author wuzhigang
 * @date 2023-11-23
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/business/importUser")
public class CaseImportUserController extends BaseController {

    private final ICaseImportUserService caseImportUserService;
    private final ISysUserService userService;

    /**
     * 查询用户导入记录列表
     */
    @GetMapping("/list")
    public TableDataInfo<CaseImportUserVo> list(CaseImportUserBo bo, PageQuery pageQuery) {
        return caseImportUserService.queryPageList(bo, pageQuery);
    }

    /**
     * excel导入数据
     *
     * @param file          导入文件
     * @param loginIdentity 身份
     */
    @Log(title = "excel导入数据", businessType = BusinessType.IMPORT)
    @PostMapping(value = "/excelData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<Map<String, String>> excelData(@RequestPart("file") MultipartFile file, String loginIdentity) throws Exception {
        // 获取租户所有用户
        List<SysUserVo> list = userService.selectUserList(new SysUserBo());
        // 获取手机号列表
        List<String> phoneList = list.stream().map(SysUserVo::getPhonenumber).collect(Collectors.toList());
        // 导入批次
        String importBatch = DateUtil.format(new DateTime(), "yyyyMMddHHmmss");
        ExcelResult<CaseExcelImportUserVo> result = ExcelUtil.importExcel(file.getInputStream(), CaseExcelImportUserVo.class, new CaseUserImportListener(phoneList, importBatch, loginIdentity));

        for (CaseExcelImportUserVo vo: result.getList()
             ) {
            if(StringUtils.isBlank(vo.getPhonenumber())){
                throw new ServiceException("导入失败，手机号码不能为空");
            }else{
                if(!isValidPhoneNumber(vo.getPhonenumber())){
                    throw new ServiceException("导入失败，手机号码："+vo.getPhonenumber()+" 不正确");
                }

            }
        }

        Map<String, String> resultMap = new HashMap<>();
        resultMap.put("importBatch", importBatch);
        resultMap.put("result", result.getAnalysis());
        return R.ok(resultMap);
    }


    /**
     * csv导入数据
     *
     * @param file          导入文件
     * @param loginIdentity 身份
     */
    @Log(title = "csv导入数据", businessType = BusinessType.IMPORT)
    @PostMapping(value = "/csvData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    public R<Map<String, Object>> csvData(@RequestPart("file") MultipartFile file, String loginIdentity) throws Exception {
        // 获取租户所有用户
        List<SysUserVo> list = userService.selectUserList(new SysUserBo());
        // 获取手机号列表
        List<String> phoneList = list.stream().map(SysUserVo::getPhonenumber).collect(Collectors.toList());
        // 导入批次
        String importBatch = DateUtil.format(new DateTime(), "yyyyMMddHHmmss");

        String userCodeStr = "H0UID" + DateUtil.format(new DateTime(), "yyyyMMddHHmmss");

        Long loginUserId = LoginHelper.getUserId();

        // 导入数据列表
        List<CaseImportUserBo> boList = new ArrayList<>();

        int i = 0;
        // 读取csv文件，获取导入用户列表
        CSVReader csvReader = new CSVReaderBuilder(
            new BufferedReader(
                new InputStreamReader(file.getInputStream(), "GBK"))).build();
        Iterator<String[]> iterator = csvReader.iterator();

        while (iterator.hasNext()) {
            String[] next = iterator.next();
            //去除第一行的表头，从第二行开始
            if (i >= 1) {
                if(StringUtils.isBlank(next[1])){
                    throw new ServiceException("导入失败，手机号码不能为空");
                }else{
                    if(!isValidPhoneNumber(next[1])){
                        throw new ServiceException("导入失败，手机号码："+next[1]+" 不正确");
                    }

                }
                CaseImportUserBo bo = new CaseImportUserBo();
                // 用户姓名
                bo.setNickName(next[0]);
                // 手机号
                bo.setPhonenumber(next[1]);
                // 组织名称
                bo.setOrganizationName(next[2]);
                // 职称
                if (StringUtils.isNotBlank(next[3])) {
                    String title = "";
                    if (UserConstants.TITLE_ONE_VALUE.equals(next[3])) {
                        title = UserConstants.TITLE_ONE_KEY;
                    } else if (UserConstants.TITLE_TWO_VALUE.equals(next[3])) {
                        title = UserConstants.TITLE_TWO_KEY;
                    } else if (UserConstants.TITLE_THREE_VALUE.equals(next[3])) {
                        title = UserConstants.TITLE_THREE_KEY;
                    } else if (UserConstants.TITLE_FOUR_VALUE.equals(next[3])) {
                        title = UserConstants.TITLE_FOUR_KEY;
                    }
                    bo.setTitle(title);
                }

                if(StringUtils.isNotBlank(next[4])){
                    // 解析次数
                    bo.setCaseAnalysisTimes(Integer.parseInt(next[4]));
                }

                if (phoneList.contains(next[1])) {
                    // 电话号码匹配，用户已存在
                    bo.setUserStatus(UserConstants.IMPORT_UPDATE);
                } else {
                    // 用户新增
                    bo.setUserStatus(UserConstants.IMPORT_ADD);
                }
                // 用户编码
                bo.setUserCode(userCodeStr + String.format("%05d", i));
                // 手机号作为用户账号
                bo.setUserName(next[1]);
                // 身份
                bo.setLoginIdentity(loginIdentity);
                // 导入批次
                bo.setImportBatch(importBatch);
                // 导入状态 - 未导入
                bo.setImportStatus(UserConstants.NOT_IMPORTED);
                // 创建用户
                bo.setCreateBy(loginUserId);

                boList.add(bo);
            }
            i++;
        }
        // 用户批量导入
        caseImportUserService.insertBatch(boList);
        // 返回信息
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("importBatch", importBatch);
        resultMap.put("count", boList.size());
        return R.ok(resultMap);
    }

    /**
     * 获取病例用户excel导入模板
     */
    @RequestMapping("/importExcelTemplate")
    public void importExcelTemplate(HttpServletResponse response) {
        ExcelUtil.exportExcel(new ArrayList<>(), "病例用户数据", CaseExcelImportUserVo.class, response);
    }

    /**
     * 获取病例用户csv导入模板
     */
    @SaIgnore
    @PostMapping("/importCsvTemplate")
    public void importCsvTemplate(HttpServletResponse response) throws IOException {

        // 响应正文
        response.reset();
        response.setContentType("application/octet-stream");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码
        String fileName = URLEncoder.encode("用户导入模版", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".csv");

        Writer writer = new OutputStreamWriter(response.getOutputStream(), "gbk");

        CSVWriter csvWriter = new CSVWriter(
            writer,
            CSVWriter.DEFAULT_SEPARATOR,
            CSVWriter.NO_QUOTE_CHARACTER,
            CSVWriter.NO_ESCAPE_CHARACTER,
            CSVWriter.DEFAULT_LINE_END);

        // 写表头信息
        csvWriter.writeNext(new String[]{"用户姓名", "手机号", "组织名称", "职称", "解析次数"});

        csvWriter.flush();

        writer.close();
    }

    /**
     * 用户数据导入系统用户
     *
     * @param bo
     * @return
     * @throws Exception
     */
    @Log(title = "用户数据导入系统用户")
    @PostMapping("/dateToSysUser")
    public R<Void> dataToSysUser(CaseImportUserBo bo) throws Exception {
        if (StringUtils.isBlank(bo.getImportBatch())) {
            throw new Exception("导入批次不能为空！");
        }
        // 根绝批次查询导入数据
        List<CaseImportUserVo> caseUserList = caseImportUserService.queryList(bo);
        // 获取租户所有用户
        List<SysUserVo> sysUserVoList = userService.selectUserList(new SysUserBo());

        List<SysUserBo> boList = new ArrayList<>();

        for (CaseImportUserVo vo : caseUserList
        ) {
            SysUserBo sysUserBo = new SysUserBo();
            BeanUtil.copyProperties(vo, sysUserBo);
            // 用户不存在
            if (vo.getUserStatus().equals(UserConstants.IMPORT_ADD)) {
                sysUserBo.setUserId(null);
            } else if (vo.getUserStatus().equals(UserConstants.IMPORT_UPDATE)) {
                // 根据手机号获取系统用户表已存在用户信息
                SysUserVo sysUserVo = sysUserVoList.stream().filter(o -> o.getPhonenumber().equals(vo.getPhonenumber())).findFirst().get();
                // 用户ID不变
                sysUserBo.setUserId(sysUserVo.getUserId());
            }
            boList.add(sysUserBo);
        }
        // 新增或更新系统用户表
        userService.insertOrUpdateBatch(boList);

        // 批量更新导入状态
        caseImportUserService.updateStatusBatch(caseUserList);

        return R.ok();
    }

    /**
     * 导出用户导入记录列表
     */
    @Log(title = "导出用户导入记录列表", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(CaseImportUserBo bo, HttpServletResponse response) {
        List<CaseImportUserVo> list = caseImportUserService.queryList(bo);
        ExcelUtil.exportExcel(list, "用户导入记录", CaseImportUserVo.class, response);
    }

    /**
     * 获取用户导入记录详细信息
     *
     * @param userId 主键
     */
    @GetMapping("/{userId}")
    public R<CaseImportUserVo> getInfo(@NotNull(message = "主键不能为空")
                                       @PathVariable Long userId) {
        return R.ok(caseImportUserService.queryById(userId));
    }

    /**
     * 新增用户导入记录
     */
    @Log(title = "新增用户导入记录", businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody CaseImportUserBo bo) {
        return toAjax(caseImportUserService.insertByBo(bo));
    }

    /**
     * 修改用户导入记录
     */
    @Log(title = "修改用户导入记录", businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody CaseImportUserBo bo) {
        return toAjax(caseImportUserService.updateByBo(bo));
    }

    /**
     * 删除用户导入记录
     *
     * @param userIds 主键串
     */
    @Log(title = "删除用户导入记录", businessType = BusinessType.DELETE)
    @DeleteMapping("/{userIds}")
    public R<Void> remove(@NotEmpty(message = "主键不能为空")
                          @PathVariable Long[] userIds) {
        return toAjax(caseImportUserService.deleteWithValidByIds(List.of(userIds), true));
    }

    // 正则验证手机号
    public static boolean isValidPhoneNumber(String phoneNumber) {
        // 使用正则表达式匹配手机号码格式
        String regex = "^(?:(?:\\+|00)86)?1[3-9]\\d{9}$";

        // 进行匹配
        Pattern pattern = Pattern.compile(regex);
        return pattern.matcher(phoneNumber).matches();
    }
}
