package com.yeechart.dotMatrix.signage;

import com.yeechart.dotMatrix.canvas.DotMatrixConversionUtil;
import com.yeechart.dotMatrix.crc.CustomCRC32Util;
import com.yeechart.dotMatrix.minilzo.MiniLZO;
import com.yeechart.dotMatrix.minilzo.MiniLZOUtil;
import com.yeechart.dotMatrix.minilzo.bean.MInt;
import com.yeechart.dotMatrix.oss.LatticeOSSUpload;
import com.yeechart.dotMatrix.oss.OSSUpload;
import com.yeechart.dotMatrix.signage.bean.mizilzo.BitmapDataVo;
import com.yeechart.dotMatrix.signage.bean.mizilzo.MiniLZOVo;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import com.yeechart.dotMatrix.util.OtherUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.stream.Collectors;

/**
 * 对 点阵图 文件操作
 */
@Component
public class SignageFileUtil {
    /**
     * 终端类总路径名称
     */
    public static final String ROOT_FILE_NAME = "Device/";
    /**
     * 默认的文件名称
     */
    public static final String ROOT_FILE_TYPE_NAME = ".txt";
    public static String fileName = "device/020201/lattice/";//路径;
    protected static Logger logger = LoggerFactory.getLogger(SignageFileUtil.class);
    //private ThreadPoolExecutor threadPoolTaskExecutor = ThreadPoolTaskExecutor.getInstance().getThreadPoolExecutor();

    @javax.annotation.Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Autowired
    private LatticeOSSUpload latticeOSSUpload;

    @Autowired
    private OSSUpload ossUpload;
    /**
     * 获取最新的点阵图文件对象
     *
     * @param dId       设备ID
     * @param typeCode  功能code
     * @param isDefault 是否是默认图
     * @return
     */
    public  BitmapDataVo getLastBitmapDataVo(String dId, String typeCode, String sessionId, boolean isDefault) {
        if (isDefault) {
            typeCode = "D" + typeCode;
        }

        String url = "http://" + ossUpload.getEndpoint() + "/" + fileName + dId + "/" + sessionId + "/" + typeCode;

        BitmapDataVo bitmapDataVo = new BitmapDataVo();
        bitmapDataVo.setTypeCode(typeCode);
        bitmapDataVo.setPath(url);


        return getFileBitmapArrays(bitmapDataVo);
    }


    /**
     * 删除点阵图
     * @param dId 设备ID
     */
    public void deleteSignageDotMatrix(String dId){

        String url = "http://" + ossUpload.getEndpoint() + "/" + fileName + dId ;

        latticeOSSUpload.deleteFolderAndSubFolders(url);


    }

    /**
     * 从 指定路径中，获取对应的文件夹数据，并解压数据合并为原始数据
     *
     * @return
     */
    public  BitmapDataVo getFileBitmapArrays(BitmapDataVo bitmapDataVo) {


        try {

            Map<String, byte[]> fileMap = new HashMap<>();

            CompletableFuture<Map<String, byte[]>> completableFuture = latticeOSSUpload.listFilesByPath(bitmapDataVo.getPath());
            fileMap = completableFuture.get();

            if (fileMap.isEmpty()) {
                return null;
            }

            //排序
            List<Map.Entry<String, byte[]>> entries = new ArrayList<>(fileMap.entrySet());

            Map<String, Integer> sizeMap = new HashMap<>();

            // 定义比较器，根据文件名最后两位数字进行排序
            entries.sort((entry1, entry2) -> {
                String name1 = entry1.getKey();
                String name2 = entry2.getKey();

                int lastDotIndex = name1.lastIndexOf('.');
                name1 = name1.substring(0, lastDotIndex);

                lastDotIndex = name2.lastIndexOf('.');
                name2 = name2.substring(0, lastDotIndex);


                int a1 = Integer.parseInt(name1.substring(name1.length() - 2));
                int a2 = Integer.parseInt(name2.substring(name2.length() - 2));
                return Integer.compare(a1, a2);
            });

            // 根据排序后的列表构造一个新的LinkedHashMap，以保持排序顺序
            Map<String, byte[]> sortedMap = new LinkedHashMap<>();
            for (Map.Entry<String, byte[]> entry : entries) {
                String name = entry.getKey();
                sortedMap.put(name, entry.getValue());

            }

            //整图的原始数据的大小 sizeMap 的value 总和
            String fileName = null;
            Integer ogSize = null;

            byte[] data1 = new byte[ SignageDrawUtil.height * SignageDrawUtil.width + 4] ;//默认使用完整图

            int length = 0;

            Map<String, MiniLZOVo> miniLZOVoList = new HashMap<>();

            for (Map.Entry<String, byte[]> entry : sortedMap.entrySet()) {
                fileName = entry.getKey();

                ogSize = SignageFileUtil.fileNameToLastFileSize(fileName);

//                System.out.println("文件大小 ogSize " +ogSize+"  fileName " +fileName);

                byte[] dataBytes = entry.getValue();

                //解压缩
                byte[] dataBytes2 = new byte[ogSize];
                MInt outL2 = new MInt();

                MiniLZO.lzo1x_decompress(dataBytes, ogSize, dataBytes2, outL2);

//                logger.info("解压缩后的长度 outLen  len:" +outL2.v);
                System.arraycopy(dataBytes2, 0, data1, length, outL2.v);

                MiniLZOVo miniLZOVo = new MiniLZOVo();
                miniLZOVo.setOgSize(ogSize);
                miniLZOVo.setData(dataBytes);
                miniLZOVo.setCrc32(CustomCRC32Util.calculateCRC32(dataBytes2));
                miniLZOVoList.put(fileName, miniLZOVo);

                length = length + ogSize;

            }
            byte[] data  ;
            if(length == SignageDrawUtil.height * SignageDrawUtil.width + 4){
                data = data1;
            }else{
                data = new byte[length ] ;
                System.arraycopy(data1, 0, data, 0, data.length);
            }


            byte[] dataBytes3 = new byte[data.length - 4];
            System.arraycopy(data, 0, dataBytes3, 0, data.length - 4);

            //将 16点阵数据 转换为 二进制点阵数据
            byte[] twoBytes = DotMatrixConversionUtil.sixteenTo2Lattice(data);

            bitmapDataVo.setMiniLZOVoList(miniLZOVoList);
            bitmapDataVo.setTwoData(twoBytes);

            return bitmapDataVo;
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("获取 点阵图文件 ：" + e + "  路径为 " + bitmapDataVo.getPath());

        }

        return null;
    }


    /************************************** 处理的点阵数据对象  **************************************/

    /**
     * 将完整的点阵图数据 转换为 点整图对象
     *
     * @param twoBytes
     * @param deId
     * @param path
     * @param typeCode
     * @param isDefault
     * @return
     */
    public  BitmapDataVo dealWithBitmapDataVo(byte[] twoBytes, String deId, String path, String typeCode, boolean isDefault) {
        BitmapDataVo bitmapDataVo = new BitmapDataVo();

        bitmapDataVo.setTwoData(twoBytes);

        bitmapDataVo.setTime(System.currentTimeMillis());

        //区分默认点阵图
        if (isDefault) {
            typeCode = "D" + typeCode;
        }
        bitmapDataVo.setTypeCode(typeCode);
        bitmapDataVo.setPath(path + typeCode);

        //保存文件
        Map<String, MiniLZOVo> sizeMap = dealWithMiniLZOVo(typeCode, twoBytes);


        bitmapDataVo.setMiniLZOVoList(sizeMap);

        return bitmapDataVo;
    }


    /**
     * 将完整的点阵图数据 进行 分割并压缩
     *
     * @param typeCode
     * @param twoBytes
     * @return
     */
    public  Map<String, MiniLZOVo> dealWithMiniLZOVo(String typeCode, byte[] twoBytes) {

        Map<String, MiniLZOVo> sizeMap = new HashMap<>();


        // 将二进制点阵图转换为16进制点阵图
        byte[] dataBytes2 = DotMatrixConversionUtil.twoTo16Lattice(twoBytes);

        //2024/04/09 新增 在整体点阵数据后面追加整体CRC32的值
        //进行CRC32算法
        long crc32 = CustomCRC32Util.calculateCRC32(dataBytes2);
        byte[] crc32Bytes = OtherUtil.longToByteArray(crc32, 4);//固定4位

        byte[] dataBytes = new byte[dataBytes2.length + crc32Bytes.length];

        System.arraycopy(dataBytes2, 0, dataBytes, 0, dataBytes2.length);
        System.arraycopy(crc32Bytes, 0, dataBytes, dataBytes2.length, crc32Bytes.length);

        //将16进制点阵图进行压缩
        List<MiniLZOVo> miniLZOVoList = MiniLZOUtil.getInstance().subMiniLZO(dataBytes);

        //生成对应的文件名称
        for (int i = 0; i < miniLZOVoList.size(); i++) {

            String fileName = typeCode +
                    (i < 10 ? "0" + i : i) + ROOT_FILE_TYPE_NAME;

            MiniLZOVo miniLZOVo = miniLZOVoList.get(i);

            sizeMap.put(fileName, miniLZOVo);
        }

        return sizeMap;
    }





    /**
     * 由于不使用数据库以及，OSS中不能存在原字节大小的问题
     * 根据type 得到最后一个文件的大小
     * @param fileName
     * @return
     */
    public static int fileNameToLastFileSize(String fileName){

        /**
         *  03 8884
         * 000000 01010100 01010101 00010000 00010001
         * 010001FF00 010001FF01 010001FF02 010001FF03 010001FF04   010001FF05 010001FFFE
         * 02 3764
         * 0100010000 0100010001 0100010002 0100010003 0100010004 0100010005
         * 01000100FE 01000101FF 01000102FF 01000103FF
         */

        fileName = fileName.replace(ROOT_FILE_TYPE_NAME,"");
        fileName = fileName.substring(fileName.lastIndexOf('/')+1);

        String typeCode = fileName.substring(0,fileName.length()-2);

        int fileNumber = Integer.parseInt(fileName.substring(fileName.length()-2));
        if(fileNumber <=2){
            return 10000;
        }
        if( typeCode.startsWith("00") // 关机画面
                ||  "01".equals(typeCode.substring(2,4)) //右屏相关
                ||  "FF".equals(typeCode.substring(typeCode.length() - 4,typeCode.length() - 2))//倒数第二个为FF
        ){
            if(fileNumber == 3 ){
                return 10000;
            }
            return 8884;
        }else{
            return 3764;
        }
    }

}
