package com.jeeplus.test.jobPosion.controller;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.jeeplus.aop.demo.annotation.DemoMode;
import com.jeeplus.aop.logging.annotation.ApiLog;
import com.jeeplus.core.excel.ExcelOptions;
import com.jeeplus.core.excel.ExportMode;
import com.jeeplus.core.excel.utils.EasyPoiUtil;
import com.jeeplus.core.query.QueryWrapperGenerator;
import com.jeeplus.sys.constant.enums.LogTypeEnum;
import com.jeeplus.sys.domain.Office;
import com.jeeplus.sys.service.OfficeService;
import com.jeeplus.test.jobPosion.domain.JobPosition;
import com.jeeplus.test.jobPosion.domain.Position;
import com.jeeplus.test.jobPosion.domain.PositionLog;
import com.jeeplus.test.jobPosion.enums.PositionTypeEnum;
import com.jeeplus.test.jobPosion.service.JobPositionService;
import com.jeeplus.test.jobPosion.service.PositionLogService;
import com.jeeplus.test.jobPosion.service.PositionService;
import com.jeeplus.test.jobPosion.service.dto.JobPositionDTO;
import com.jeeplus.test.jobPosion.service.dto.PositionLogDTO;
import com.jeeplus.test.jobPosion.service.mapstruct.JobPositionWrapper;
import com.jeeplus.test.jobPosion.utils.BeanUtils;
import com.jeeplus.test.projectRecords.constant.enums.ProjectStatusEnum;
import com.jeeplus.test.projectRecords.constant.enums.ProjectTypeEnum;
import com.jeeplus.test.projectRecords.constant.enums.YesOrNoEnum;
import com.jeeplus.test.projectRecords.domain.Project;
import com.jeeplus.test.projectRecords.service.dto.ProjectDTO;
import com.jeeplus.test.projectRecords.service.mapstruct.ProjectWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import liquibase.pro.packaged.S;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Api("职位管理")
@RestController
@RequestMapping(value = "/job/job_position")
public class JobPositionController {

    @Autowired
    private JobPositionService jobPositionService;

    @Autowired
    private PositionService positionService;

    @Autowired
    private OfficeService officeService;

    @Autowired
    private PositionLogService positionLogService;

    /**
     * 查询职位列表
     * @param jobPosition
     * @param page
     * @return
     * @throws Exception
     */
    @ApiLog("查询职位列表")
    @PreAuthorize("hasAuthority('job:job_position:list')")
    @GetMapping("list")
    public ResponseEntity<IPage<JobPosition>> data(JobPosition jobPosition, Page<JobPosition> page) throws Exception {
        QueryWrapper<JobPosition> queryWrapper = QueryWrapperGenerator.buildQueryCondition ( jobPosition, JobPosition.class );
        IPage<JobPosition> result = jobPositionService.findList (page,queryWrapper);
        return ResponseEntity.ok (result);
    }

    /**
     * 查询职位数据
     * @param id
     * @return
     */
    @ApiLog("查询职位详情")
    @PreAuthorize ("hasAnyAuthority('job:position:view','job:position:add','job:position:edit')")
    @GetMapping("queryById")
    public ResponseEntity queryById(@RequestParam("id") String id) {
        JobPosition jobPosition = jobPositionService.getById ( id );
        return ResponseEntity.ok (jobPosition);
    }

    /**
     * 添加职位
     * @param jobPositionDTO
     * @return
     */
    @ApiLog(value = "修改/新增职位", type = LogTypeEnum.SAVE)
    @PreAuthorize("hasAnyAuthority('job:job_position:save','job:job_position:edit')")
    @PostMapping("save")
    public ResponseEntity save(@Valid @RequestBody JobPositionDTO jobPositionDTO,HttpServletRequest request) {
        JobPosition jobPosition = JobPositionWrapper.INSTANCE.toEntity(jobPositionDTO);
        JobPosition oldPosition = null;
        PositionLogDTO positionLogDTO = new PositionLogDTO();
        if(StrUtil.isEmpty(jobPositionDTO.getId())){
            List<JobPosition> jobPositions = jobPositionService.list(new QueryWrapper<JobPosition>()
                    .eq("name", jobPositionDTO.getName()));
            if(CollectionUtil.isNotEmpty(jobPositions)){
                return ResponseEntity.badRequest().body("职位名称不可以重复");
            }
            jobPosition.setUseFlag("1");
            positionLogDTO.setType(PositionTypeEnum.JOB_POSITION.getValue());
            positionLogDTO.setOperationType("新建职位");
            positionLogDTO.setOperationContent("新建职位: "+jobPositionDTO.getName());
        }else{
            List<JobPosition> jobPositions = jobPositionService.list(new QueryWrapper<JobPosition>()
                    .ne("id",jobPositionDTO.getId()).eq("name", jobPositionDTO.getName()));
            if(CollectionUtil.isNotEmpty(jobPositions)){
                return ResponseEntity.badRequest().body("职位名称不可以重复");
            }
            oldPosition = jobPositionService.getById(jobPosition.getId());
            if(ObjectUtil.isNotEmpty(oldPosition)){
                if(StrUtil.isNotEmpty(oldPosition.getPositionId())){
                    Position byId = positionService.getById(oldPosition.getPositionId());
                    if (ObjectUtil.isNotEmpty(byId)) {
                        if(StrUtil.isNotEmpty(byId.getName())){
                            oldPosition.setPositionId(byId.getName());
                        }
                    }
                }
                if(StrUtil.isNotEmpty(oldPosition.getOfficeId())){
                    Office office = officeService.getById(oldPosition.getOfficeId());
                    if (ObjectUtil.isNotEmpty(office)) {
                        if(StrUtil.isNotEmpty(office.getName())){
                            oldPosition.setOfficeId(office.getName());
                        }
                    }
                }
            }
            positionLogDTO.setType(PositionTypeEnum.JOB_POSITION.getValue());
            positionLogDTO.setOperationType("修改职位");
        }
        try{
            jobPositionService.saveOrUpdate(jobPosition);
        }catch (Exception e){
            if (StrUtil.isNotEmpty(jobPosition.getId())){
                String changedFields = BeanUtils.getChangedFields(jobPosition, new JobPosition());
                positionLogDTO.setOperationContent(changedFields);
            }
            positionLogDTO.setOperationResult("失败");
            positionLogService.saveLog(positionLogDTO,request);
            return ResponseEntity.badRequest().body  ("职位保存失败");
        }

        if (StrUtil.isNotEmpty(jobPositionDTO.getId())){
            JobPosition byId = jobPositionService.getById(jobPosition.getId());
            if(ObjectUtil.isNotEmpty(byId)){
                if(StrUtil.isNotEmpty(byId.getPositionId())){
                    Position byId1 = positionService.getById(byId.getPositionId());
                    if (ObjectUtil.isNotEmpty(byId1)) {
                        if(StrUtil.isNotEmpty(byId1.getName())){
                            byId.setPositionId(byId1.getName());
                        }
                    }
                }
                if(StrUtil.isNotEmpty(byId.getOfficeId())){
                    Office office = officeService.getById(byId.getOfficeId());
                    if (ObjectUtil.isNotEmpty(office)) {
                        if(StrUtil.isNotEmpty(office.getName())){
                            byId.setOfficeId(office.getName());
                        }
                    }
                }
            }
            String changedFields = BeanUtils.getChangedFields(byId, oldPosition);
            positionLogDTO.setOperationContent(changedFields);
        }
        positionLogDTO.setOperationResult("成功");
        positionLogService.saveLog(positionLogDTO,request);

        return ResponseEntity.ok ("保存职位成功");
    }

    /**
     * 删除职位
     * @param ids
     * @return
     */
    @ApiLog(value = "删除职位", type = LogTypeEnum.SAVE)
    @PreAuthorize ("hasAuthority('job:job_position:del')")
    @DeleteMapping("delete")
    public ResponseEntity delete(String ids,HttpServletRequest request) {
        List<PositionLogDTO> positionLogDTOList = new ArrayList<>();

        String idArray[] =ids.split(",");
        List<JobPosition> jobPositions = jobPositionService.listByIds(Lists.newArrayList(idArray));
        jobPositions.stream().forEach(item->{
            PositionLogDTO positionLogDTO = new PositionLogDTO();
            positionLogDTO.setType(PositionTypeEnum.JOB_POSITION.getValue());
            positionLogDTO.setOperationType("删除职位");
            positionLogDTO.setOperationContent("删除职位: "+item.getName());
            positionLogDTOList.add(positionLogDTO);
        });
        try{
            jobPositionService.removeByIds (Lists.newArrayList (idArray));
        }catch (Exception e) {
            positionLogDTOList.stream().forEach(item->{
                item.setOperationResult("失败");
            });
            positionLogService.saveLogBatch(positionLogDTOList,request);
            return ResponseEntity.badRequest().body  ("职位删除失败");
        }

        positionLogDTOList.stream().forEach(item->{
            item.setOperationResult("成功");
        });
        positionLogService.saveLogBatch(positionLogDTOList,request);

        return ResponseEntity.ok ("删除职位成功");
    }

    /**
     * 修改职位启动状态
     * @param ids
     * @return
     */
    @ApiLog(value = "修改职位启用状态", type = LogTypeEnum.SAVE)
    @PreAuthorize ("hasAnyAuthority('job:job_position:del','job:job_position:edit','job:job_position:add')")
    @PostMapping("changeUseFlag/{useFlag}")
    public ResponseEntity changeUseFlag(String ids,@PathVariable("useFlag") String useFlag,HttpServletRequest request) {
        String idArray[] =ids.split(",");
        ArrayList<String> strings = Lists.newArrayList(idArray);

        List<PositionLogDTO> positionLogDTOList = new ArrayList<>();

        List<JobPosition> jobPositions = jobPositionService.listByIds(strings);
        jobPositions.stream().forEach(item->{
            PositionLogDTO positionLogDTO = new PositionLogDTO();
            positionLogDTO.setType(PositionTypeEnum.JOB_POSITION.getValue());
            positionLogDTO.setOperationType("修改职位启用状态");
            if("1".equals(useFlag)){
                positionLogDTO.setOperationContent("修改职位“"+item.getName()+"”的启用状态为:启用");
            }else{
                positionLogDTO.setOperationContent("修改职位“"+item.getName()+"”的启用状态为:停用");
            }
            positionLogDTOList.add(positionLogDTO);
        });
        try{
            jobPositionService.updateUseFlagById(strings,useFlag);
        }catch (Exception e){
            positionLogDTOList.stream().forEach(item->{
                item.setOperationResult("失败");
            });
            positionLogService.saveLogBatch(positionLogDTOList,request);
            return ResponseEntity.badRequest().body  ("修改职位状态失败");
        }

        positionLogDTOList.stream().forEach(item->{
            item.setOperationResult("成功");
        });
        positionLogService.saveLogBatch(positionLogDTOList,request);

        return ResponseEntity.ok ("修改职位状态成功");
    }

    /**
     * 查询全部职务
     * @return
     */
    @ApiLog("查询全部职务")
    @PreAuthorize ("hasAnyAuthority('job:position:view','job:job_position:save','job:job_position:edit')")
    @GetMapping("queryAllPosition")
    public ResponseEntity<List<Position>> queryAllPosition() {
        List<Position> result = positionService.list ();
        return ResponseEntity.ok (result);
    }

    /**
     * 查询全部部门
     * @return
     */
    @ApiLog("查询全部部门")
    @PreAuthorize ("hasAnyAuthority('job:job_position:view','job:job_position:save','job:job_position:edit')")
    @GetMapping("queryAllOffice")
    public ResponseEntity<List<Office>> queryAllOffice() {
        QueryWrapper<Office> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("type","2");
        List<Office> result = officeService.list (queryWrapper);
        return ResponseEntity.ok (result);
    }

    /**
     * 下载职位导入模板
     *
     * @param response
     * @return
     */
    @GetMapping("import/template")
    @PreAuthorize("hasAnyAuthority('job:job_position:export')")
    @ApiOperation(value = "下载模板")
    public void importFileTemplate(HttpServletResponse response, HttpServletRequest request) {
        try {
            InputStream inputStream = this.getClass().getResourceAsStream("/dot/职位导入模板.xlsx");
            //强制下载不打开
            response.setContentType("application/force-download");
            OutputStream out = response.getOutputStream();
            //使用URLEncoder来防止文件名乱码或者读取错误
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode("job_position_template.xlsx", "UTF-8"));
            int b = 0;
            byte[] buffer = new byte[1000000];
            while (b != -1) {
                b = inputStream.read(buffer);
                if (b != -1) out.write(buffer, 0, b);
            }
            inputStream.close();
            out.close();
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 导入职位数据
     *
     * @return
     */
    @DemoMode
    @PreAuthorize("hasAnyAuthority('job:job_position:import')")
    @PostMapping("import")
    @ApiLog(value = "导入职位数据excel", type = LogTypeEnum.IMPORT)
    public ResponseEntity importFile(MultipartFile file,HttpServletRequest request) throws IOException{

        ArrayList<JobPosition> arrayList = new ArrayList<>();
        HashMap<String,String> hashMap = new HashMap<>();

        List<JobPositionDTO> listA = new ArrayList<>();
        //获取职位sheet
        listA = EasyPoiUtil.importSheetExcel(file, 0, 1, 0,1, JobPositionDTO.class);
        //去除excel中的空行
        listA = getExcelList(listA);
        //导入前检测数据
        String resultA = importDecide(listA, arrayList, hashMap);
        if(StrUtil.isNotEmpty(resultA)){
            //有返回值，说明导入的数据不正确。向用户抛提示
            return ResponseEntity.badRequest().body  (resultA);
        }
        //判断文件中是否有重复的文号
        if(hashMap.size() != listA.size()){
            return ResponseEntity.badRequest().body  ("文件中存在重复的职位名称");
        }
        //导入数据
        jobPositionService.saveBatch(arrayList);

        List<PositionLogDTO> positionLogDTOList = new ArrayList<>();
        arrayList.stream().forEach(item->{
            PositionLogDTO positionLogDTO = new PositionLogDTO();
            positionLogDTO.setType(PositionTypeEnum.JOB_POSITION.getValue());
            positionLogDTO.setOperationType("导入职位");
            positionLogDTO.setOperationContent("导入职位: "+item.getName());
            positionLogDTO.setOperationResult("成功");
            positionLogDTOList.add(positionLogDTO);
        });
        positionLogService.saveLogBatch(positionLogDTOList,request);

        return ResponseEntity.ok("已成功导入 " + arrayList.size() + " 条数据");
    }

    public String importDecide(List<JobPositionDTO> list, ArrayList<JobPosition> arrayList, HashMap<String,String> hashMap){
        HashMap<String,String> noMap = new HashMap<>();
        ArrayList<String> lists = new ArrayList<>();
        for (JobPositionDTO jobPositionDTO : list) {
            if(ObjectUtil.isEmpty(jobPositionDTO)){
                continue;
            }

            if(StrUtil.isEmpty(jobPositionDTO.getName())){
                return "文件中有职位为空，请重新填写";
            }
            if(StrUtil.isNotEmpty(jobPositionDTO.getName())){
                JobPosition jobPosition = jobPositionService.getOne(new QueryWrapper<JobPosition>().eq("name", jobPositionDTO.getName()));
                if(ObjectUtil.isNotEmpty(jobPosition)){
                    return "文件中有职位已在系统中存在，请重新填写";
                }
            }
            if(StrUtil.isNotEmpty(jobPositionDTO.getName())){
                JobPosition jobPosition = jobPositionService.getOne(new QueryWrapper<JobPosition>().eq("no", jobPositionDTO.getNo()));
                if(ObjectUtil.isNotEmpty(jobPosition)){
                    return "文件中有职位编码已在系统中存在，请重新填写";
                }
            }
            if(StrUtil.isNotEmpty(jobPositionDTO.getOfficeId())){
                Office office = officeService.getOne(new QueryWrapper<Office>().eq("name", jobPositionDTO.getOfficeId()));
                if(ObjectUtil.isNotEmpty(office)){
                    jobPositionDTO.setOfficeId(office.getId());
                }else{
                    return "文件中有部门在系统中不存在，请重新填写";
                }
            }
            if(StrUtil.isNotEmpty(jobPositionDTO.getPositionId())){
                Position position = positionService.getOne(new QueryWrapper<Position>().eq("name", jobPositionDTO.getPositionId()));
                if(ObjectUtil.isNotEmpty(position)){
                    jobPositionDTO.setPositionId(position.getId());
                }else{
                    return "文件中有对应职务在系统中不存在，请重新填写";
                }
            }
            if(StrUtil.isNotEmpty(jobPositionDTO.getStaffNums())){
                if(isNumeric(jobPositionDTO.getStaffNums())==false){
                    return "文件中有编制人数的格式填写不正确，请填写正整数或者不填写";
                }else{
                    int i = Integer.parseInt(jobPositionDTO.getStaffNums());
                    jobPositionDTO.setStaffNum(i);
                }
            }

            if(StrUtil.isNotEmpty(jobPositionDTO.getNo())){
                noMap.put(jobPositionDTO.getNo(),null);
                lists.add(jobPositionDTO.getNo());
            }

            //导入时，将状态设置为启用
            jobPositionDTO.setUseFlag("1");

            hashMap.put(jobPositionDTO.getName(),null);

            JobPosition jobPosition = JobPositionWrapper.INSTANCE.toEntity(jobPositionDTO);
            arrayList.add(jobPosition);
        }
        if(noMap.size()!=lists.size()){
            return "文件中的职位编码有重复值，请重新填写";
        }
        return null;
    }

    public static boolean isNumeric(String str){
        for (int i = str.length();--i>=0;){
            if (!Character.isDigit(str.charAt(i))){
                return false;
            }
        }
        return true;
    }
    public ArrayList<JobPositionDTO> getExcelList(List<JobPositionDTO> list){

        ArrayList<JobPositionDTO> jobPositionDTOS = new ArrayList<>();

        list.stream().forEach(item->{
            if(!objectCheckIsNull(item)){
                jobPositionDTOS.add(item);
            }
        });

        return jobPositionDTOS;
    }

    /**
     * 检查一个对象的所有属性值是否都是null
     * @param object
     * @return
     */
    public boolean objectCheckIsNull(Object object) {
        boolean flag = true; //定义返回结果，默认为true

        if (Objects.isNull(object)) {
            flag = true;
        } else {
            Class clazz = (Class) object.getClass(); // 得到类对象
            Field fields[] = clazz.getDeclaredFields(); // 得到所有属性
            for (Field field : fields) {
                if("serialVersionUID".equals(field.getName())){
                    continue;
                }
                field.setAccessible(true);
                Object fieldValue = null;
                try {
                    fieldValue = field.get(object); //得到属性值
                    Type fieldType = field.getGenericType();//得到属性类型
                    String fieldName = field.getName(); // 得到属性名
                } catch (Exception e){}
                if (fieldValue != null) {  //只要有一个属性值不为null 就返回false 表示对象不为null
                    flag = false;
                    break;
                }
            }
        }

        return flag;
    }

    /**
     * 导出职位数据
     *
     * @param jobPositionDTO
     * @param page
     * @param response
     * @throws Exception
     */
    @ApiLog(value = "导出职位数据", type = LogTypeEnum.EXPORT)
    @PreAuthorize("hasAnyAuthority('job:job_position:export')")
    @GetMapping("export")
    @ApiOperation(value = "导出职位excel")
    public void exportFile(JobPositionDTO jobPositionDTO, Page <JobPositionDTO> page, ExcelOptions options, HttpServletResponse response) throws Exception {
        String fileName = options.getFilename ( );
        JobPosition jobPosition = JobPositionWrapper.INSTANCE.toEntity (jobPositionDTO);
        QueryWrapper<JobPosition> queryWrapper = QueryWrapperGenerator.buildQueryCondition ( jobPosition, JobPosition.class );
        Page <JobPosition> jobPositionPage = pageAToPageB(page);
        List <JobPosition> result = new ArrayList<>();
        List <JobPositionDTO> jobPositionDTOList = new ArrayList<>();
        if ( ExportMode.current.equals ( options.getMode ( ) ) ) {
            result = jobPositionService.findList ( jobPositionPage, queryWrapper ).getRecords ( );
        } else {
            jobPositionPage.setSize ( -1 );
            jobPositionPage.setCurrent ( 0 );
            result = jobPositionService.findList ( jobPositionPage, queryWrapper ).getRecords ( );
        }
        result.stream().forEach(item->{
            JobPositionDTO jobPositionDTO1 = JobPositionWrapper.INSTANCE.toDTO(item);
            if(ObjectUtil.isNotEmpty(item.getStaffNum())){
                jobPositionDTO1.setStaffNums(jobPositionDTO1.getStaffNum().toString());
            }
            jobPositionDTOList.add(jobPositionDTO1);
        });


        EasyPoiUtil.exportExcel ( jobPositionDTOList, null,  null, JobPositionDTO.class, fileName, response );

    }
    public Page<JobPosition> pageAToPageB(Page<JobPositionDTO> page){

        Page<JobPosition> pageB = new Page<>();
        pageB.setCurrent(page.getCurrent());
        pageB.setSize(page.getSize());
        pageB.setOrders(page.getOrders());

        return pageB;
    }

    @GetMapping("getJobPositionByOff")
    public ResponseEntity getJobPositionByOff(String id){
        List<JobPosition> jobPositionList = jobPositionService.list(new QueryWrapper<JobPosition>().eq("office_id", id));
        return ResponseEntity.ok(jobPositionList);
    }

}
