package org.jeecg.modules.api.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.util.DateUtils;
import org.jeecg.common.util.RestUtil;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.api.model.CabinetModel;
import org.jeecg.modules.api.model.CabinetStocks;
import org.jeecg.modules.material.entity.BuMaterialInfo;
import org.jeecg.modules.material.entity.BuMaterialSheet;
import org.jeecg.modules.material.service.IBuMaterialInfoService;
import org.jeecg.modules.material.service.IBuMaterialSheetService;
import org.jeecg.modules.material.service.IBuMaterialStockService;
import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysDictItem;
import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.mapper.SysDictItemMapper;
import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.tool.entity.Tool;
import org.jeecg.modules.tool.service.IToolService;
import org.jeecg.modules.toolBorrowingRecord.service.IToolBorrowingRecordService;
import org.jeecg.modules.toolSheet.entity.ToolSheet;
import org.jeecg.modules.toolSheet.service.IToolSheetService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.*;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.stream.ImageOutputStream;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.GZIPOutputStream;

/**
 * 智能工具柜接口
 */
@RestController
@Api(tags="API智能工具柜对接")
@RequiredArgsConstructor
@Slf4j
@RequestMapping("/cabinet")
public class CabinetApiController {

    private final IToolService toolService;
    private final IToolSheetService toolSheetService;
    private final IToolBorrowingRecordService toolBorrowingRecordService;
    private final IBuMaterialInfoService materialInfoService;
    private final IBuMaterialSheetService materialSheetService;
    private final IBuMaterialStockService materialStockService;
    private final ISysUserService sysUserService;
    private final ISysDepartService sysDepartService;
    private final SysDictItemMapper sysDictItemMapper;

    /**
     * 工具库存信息同步接口
     * @param dto
     * @return
     */
    @ApiOperation(value="工具库存信息同步接口", notes="工具库存信息同步接口")
    @PostMapping("/sendStocks")
    public Result<String> stocks(@RequestBody CabinetStocks dto) {
        System.out.println(dto);
        return Result.OK("工具库存信息同步成功");
    }

    @ApiOperation(value="人员信息同步接口", notes="人员信息同步接口")
    @GetMapping("/receiveUsers")
    public Result<List<CabinetModel>> userList(@RequestParam(name = "userId", required = false) String userId) {
        List<CabinetModel> cabinetModelList = new ArrayList<>();

        // 根据 userId 是否为空决定查询单个用户还是所有用户
        if (StringUtils.isBlank(userId)) {
            // 查询所有用户
            List<SysUser> sysUsers = sysUserService.list();
            sysUsers.forEach(sysUser -> cabinetModelList.add(convertToCabinetModel(sysUser)));
        } else {
            // 查询单个用户
            SysUser sysUser = sysUserService.getById(userId);
            if (sysUser != null) {
                cabinetModelList.add(convertToCabinetModel(sysUser));
            }
        }

        return Result.OK(cabinetModelList);
    }
    /**
     * 查询数据 查出所有部门,并以树结构数据格式响应给前端
     *
     * @return
     */
    @ApiOperation(value="所有部门信息同步接口", notes="所有部门信息同步接口")
    @RequestMapping(value = "/queryTreeList", method = RequestMethod.GET)
    public Result<List<SysDepart>> queryTreeList(@RequestParam(name = "id", required = false) String id) {
        LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<SysDepart>();
        query.orderByAsc(SysDepart::getOrgCode);
        if(oConvertUtils.isNotEmpty(id)){
            String[] arr = id.split(",");
            query.in(SysDepart::getId,arr);
        }
        List<SysDepart> ls = this.sysDepartService.list(query);
        return Result.ok(ls);
    }

    @ApiOperation(value="3.3工具基础信息接口", notes="3.3工具基础信息接口")
    @GetMapping("/receiveToolInfo")
    public Result<List<CabinetStocks>> toolList(@RequestParam(name = "toolId", required = false) String toolId) {
        List<CabinetStocks> cabinetStocksList = new ArrayList<>();

        // 根据 toolId 是否为空决定查询单个工具还是所有工具
        if (StringUtils.isBlank(toolId)) {
            // 查询所有工具
            List<ToolSheet> toolSheets = toolSheetService.list();
            toolSheets.forEach(toolSheet -> cabinetStocksList.add(convertToToolStock(toolSheet)));
        } else {
            // 查询单个工具
            ToolSheet toolSheet = toolSheetService.getById(toolId);
            if (toolSheet != null) {
                cabinetStocksList.add(convertToToolStock(toolSheet));
            }
        }

        return Result.OK(cabinetStocksList);
    }
    /**
     * 工具大类同步接口
     * @return
     */
    @ApiOperation(value="工具大类同步接口", notes="工具大类同步接口")
    @GetMapping("/toolTypes")
    public Result<List<CabinetStocks>> tooltypes() {
        List<CabinetStocks> cabinetStocksList = toolService.list()
                .stream()
                .map(tool -> {
                    CabinetStocks cabinetStocks = new CabinetStocks();
                    cabinetStocks.setToolType(tool.getId());
                    cabinetStocks.setTypeName(tool.getName());
                    return cabinetStocks;
                }).toList();

        return Result.OK(cabinetStocksList);
    }

    @ApiOperation(value="工具出入库记录同步接口", notes="工具出入库记录同步接口")
    @PostMapping("/sendOutputInfo")
    public Result<String> outputInfo(@RequestBody CabinetStocks dto) {
        System.out.println("************************"+JSONObject.toJSONString(dto));
        if (toolBorrowingRecordService.inOutRecordSync(dto.getTools())) {
            return Result.OK("工具出入库记录同步成功");
        }else {
            return Result.error("工具出入库记录同步失败");
        }
    }

    @ApiOperation(value="物料类型字典接口", notes="物料类型字典接口")
    @GetMapping("/materialTypes")
    public Result<Map<String, String>> materialTypes() {
        List<SysDictItem> dictItems = sysDictItemMapper.selectItemsByDictCode("material_type");
        Map<String, String> dictMap = dictItems.stream().collect(Collectors.toMap(SysDictItem::getItemValue,SysDictItem::getItemText));

        return Result.OK(dictMap);
    }

    @ApiOperation(value="物料基础信息接口", notes="物料基础信息接口")
    @GetMapping("/receiveMaterialInfo")
    public Result<List<CabinetStocks>> materialList(@RequestParam(name = "materialId", required = false) String materialId) {
        List<CabinetStocks> cabinetStocksList = new ArrayList<>();

        // 根据 materialId 是否为空决定查询单个物料还是所有物料
        if (StringUtils.isBlank(materialId)) {
            // 查询所有物料
            List<BuMaterialInfo> materialInfoList = materialInfoService.list();
            materialInfoList.forEach(materialInfo -> cabinetStocksList.add(convertToMaterialStock(materialInfo)));
        } else {
            // 查询单个物料
            BuMaterialInfo materialInfo = materialInfoService.getById(materialId);
            if (materialInfo != null) {
                cabinetStocksList.add(convertToMaterialStock(materialInfo));
            }
        }

        return Result.OK(cabinetStocksList);
    }

    @ApiOperation(value="物料出入库记录同步接口", notes="物料出入库记录同步接口")
    @PostMapping("/sendMatOutputInfo")
    public Result<String> outputMInfo(@RequestBody CabinetStocks dto) {
        System.out.println("************************"+JSONObject.toJSONString(dto));
        if (materialStockService.inOutRecordSync(dto.getMaterials())) {
            return Result.OK("物料出入库记录同步成功");
        }else {
            return Result.error("物料出入库记录同步失败");
        }
    }

    /**
     * 将 SysUser 对象转换为 CabinetModel 对象
     */
    private CabinetModel convertToCabinetModel(SysUser sysUser) {
        CabinetModel cabinetModel = new CabinetModel();
        cabinetModel.setUserId(sysUser.getId());
        cabinetModel.setUserName(sysUser.getUsername());
        cabinetModel.setNickName(sysUser.getRealname());
        cabinetModel.setFaceUrl(sysUser.getFaceUrl());
        LambdaQueryWrapper<SysDepart> query = new LambdaQueryWrapper<>();
        query.eq(SysDepart::getOrgCode, sysUser.getOrgCode());
        SysDepart sysDepart = sysDepartService.getOne(query);
        cabinetModel.setOrgCode(sysDepart.getOrgCode());
        cabinetModel.setDepartId(sysDepart.getId());
        cabinetModel.setDepartName(sysDepart.getDepartName());
        cabinetModel.setRoles(sysUserService.getRole(sysUser.getUsername()));
        //不再上传人脸数据，改为在柜子上录入
//        if(StringUtils.isNotBlank(sysUser.getFaceUrl())) {
//            cabinetModel.setFaceImgStr(convertImageToBase64(sysUser.getFaceUrl()));
//        }
        return cabinetModel;
    }
    private CabinetStocks convertToToolStock(ToolSheet toolSheet) {
        CabinetStocks toolStocks = new CabinetStocks();
        toolStocks.setToolId(toolSheet.getId());
        toolStocks.setToolCode(toolSheet.getCode());
        toolStocks.setCalibrationTime(DateUtils.date2Str(toolSheet.getLastCheckDate(), DateUtils.datetimeFormat.get()));
        toolStocks.setStatus(toolSheet.getStatus());
        Tool tool = toolService.getById(toolSheet.getToolId());
        toolStocks.setToolType(tool.getId());
        toolStocks.setTypeName(tool.getName()+"("+tool.getModel()+")");
        return toolStocks;
    }
    private CabinetStocks convertToMaterialStock(BuMaterialInfo materialInfo) {
        CabinetStocks toolStocks = new CabinetStocks();
        toolStocks.setMaterialId(materialInfo.getId());
        toolStocks.setMaterialName(materialInfo.getName());
        toolStocks.setMaterialModel(materialInfo.getSpecifaction());
        toolStocks.setMaterialType(String.valueOf(materialInfo.getType()));
        BuMaterialSheet materialSheet = materialSheetService.getOne(new LambdaQueryWrapper<BuMaterialSheet>().eq(BuMaterialSheet::getMaterialId, materialInfo.getId()));
        if (materialSheet != null) {
            toolStocks.setPurchaseDate(DateUtils.date2Str(materialSheet.getPurchaseDate(), DateUtils.datetimeFormat.get()));
            toolStocks.setQuantity(materialSheet.getQuantity());
        }
        return toolStocks;
    }

    public static String convertImageToBase64(String imageUrl) {
        try {
            // 获取原始图片数据
            byte[] imageBytes = RestUtil.getRestTemplate().getForObject(imageUrl, byte[].class);
            if (imageBytes == null) {
                return null;
            }

            // 读取原始图片
            ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
            BufferedImage originalImage = ImageIO.read(inputStream);
            if (originalImage == null) {
                // 如果无法解析为图片，直接压缩原始数据
                return compressRawData(imageBytes);
            }

            // 处理透明图片 - 转换为RGB模式
            BufferedImage rgbImage = new BufferedImage(
                    originalImage.getWidth(),
                    originalImage.getHeight(),
                    BufferedImage.TYPE_INT_RGB);

            // 填充白色背景
            Graphics2D graphics = rgbImage.createGraphics();
            graphics.setColor(Color.WHITE);
            graphics.fillRect(0, 0, rgbImage.getWidth(), rgbImage.getHeight());
            graphics.drawImage(originalImage, 0, 0, null);
            graphics.dispose();

            // 使用ByteArrayOutputStream存储压缩后的图片
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

            // 使用JPEG格式压缩（JPEG通常比PNG小）
            ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
            ImageWriteParam params = writer.getDefaultWriteParam();
            params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            params.setCompressionQuality(0.85f); // 可调整，0.8-0.9之间通常能保持较好的清晰度

            ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(outputStream);
            writer.setOutput(imageOutputStream);
            writer.write(null, new IIOImage(rgbImage, null, null), params);
            writer.dispose();
            imageOutputStream.close();

            // 对压缩后的JPEG数据进行Base64编码
            return Base64.getEncoder().encodeToString(outputStream.toByteArray());
        } catch (Exception e) {
            throw new RuntimeException("压缩并转换图片到Base64失败: " + e.getMessage(), e);
        }
    }

    // 辅助方法：直接压缩原始数据
    private static String compressRawData(byte[] data) throws IOException {
        ByteArrayOutputStream compressedOutputStream = new ByteArrayOutputStream();
        try (GZIPOutputStream gzipOutputStream = new GZIPOutputStream(compressedOutputStream)) {
            gzipOutputStream.write(data);
        }
        return Base64.getEncoder().encodeToString(compressedOutputStream.toByteArray());
    }

    @Value("${cabinet.tip}")
    private String cabinetIp;
    @Value("${cabinet.manufacturer}")
    private String cabinetManufacturer;
    //    @Value("${cabinet.port}")
    //    private static Integer cabinetPort;
    private static final String FUNCTION_PATH = "/ServiceHandler.ashx?function=";
//    @ApiOperation(value="人员信息同步接口", notes="人员信息同步接口")
//    @PostMapping("/sendUsers")
    public boolean sendUsers(List<CabinetModel> cabinetModels) throws RuntimeException {
        JSONObject body = new JSONObject();
        body.put("users", JSONArray.parse(JSON.toJSONString(cabinetModels)));
        return sendRequest("receiveUsers", "users", body);
    }
//    @ApiOperation(value="向工具柜下发工单信息", notes="向工具柜下发工单信息")
//    @PostMapping("/sendWorkOrder")
    public boolean sendWorkOrder(CabinetModel cabinetModel) throws RuntimeException {
        JSONObject body = JSON.parseObject(JSON.toJSONString(cabinetModel));
        if("zhonghong".equals(cabinetManufacturer)) {
            ResponseEntity<JSONObject> response = RestUtil.request("http://15030557804.xicp.net/api/cabinet/receiveCancelOrder", HttpMethod.POST, null, body);
            validateResponse(response, "sendWorkOrder");
            return true;
        }else {
            return sendRequest("receiveOrderInfo", "OrderInfo", body);
        }
    }
//    @ApiOperation(value="向工具柜同步工具信息", notes="向工具柜同步工具信息")
//    @PostMapping("/sendToolInfo")
    public boolean sendToolInfo(@RequestBody List<CabinetStocks> dto) throws RuntimeException {
        JSONObject body = new JSONObject();
        body.put("tools", JSONArray.parse(JSON.toJSONString(dto)));
        return sendRequest("receiveToolInfo", "tools", body);
    }
    // 处理HTTP请求
    private boolean sendRequest(String function, String paramName, JSONObject data) throws RuntimeException {
        try {
            // 构建MultiValueMap
            MultiValueMap<String, String> formData = new LinkedMultiValueMap<>();
            formData.add(paramName, data.toJSONString());

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.MULTIPART_FORM_DATA);

            // 构建请求URL
            String url = String.format("http://%s%s%s", cabinetIp, FUNCTION_PATH, function);

            // 发送请求
            ResponseEntity<JSONObject> response = RestUtil.request1(url, HttpMethod.POST, headers, null, formData, JSONObject.class);

            // 处理响应
            validateResponse(response, function);

            return true;
        } catch (Exception e) {
            String errorMsg = String.format("%s失败: %s", function, e.getMessage());
            throw new RuntimeException(errorMsg, e);
        }
    }
    // 响应验证逻辑
    private void validateResponse(ResponseEntity<JSONObject> response, String operation) throws RuntimeException {
        if (response.getBody() == null) {
            throw new RuntimeException(operation + "失败，未获取到响应！");
        }
        if (!"200".equals(response.getBody().getString("code"))) {
            throw new RuntimeException(response.getBody().getString("message"));
        }
    }

}
