package com.hdkj.lt.utils.file;

import cn.hutool.core.map.MapUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Map;

@Slf4j
public class FileExtUtils {

    private final static Map<String, String> FILE_EXT_HEX;
    private final static boolean IS_VALIDATE_BYTE = true;

    static {
        FILE_EXT_HEX = MapUtil.builder(MapUtil.<String, String>newHashMap())
                .put("jpg", "FFD8FF")
                .put("jpeg", "FFD8FF")
                .put("jfif", "FFD8FF")
                .put("png", "89504E47")
                .put("gif", "47494638")
                .put("tif", "49492a00")
                .put("tiff", "49492a00")
                .put("bmp", "424d")
                .put("doc", "D0CF11E0")
                .put("docx", "504B0304")
                .put("xls", "D0CF11E0")
                .put("xlsx", "504B0304")
                .put("pdf", "255044462D312E")
                .put("zip", "504B0304")
                .put("rar", "526172")
                .put("dwg", "41433130")
                .put("xml", "3C3F786D6C")
                .put("svg", "EFBBBF3C3F")
                .put("m4a", "00000018667479706d70343200000000")
                .put("mp3", "494433")
                .put("rmvb", "2e524d46000000120001") //rmvb/rm相同
                .put("flv", "464c5601050000000900") //flv与f4v相同
                .put("mp4", "00000020667479706973")
                .put("mpg", "000001ba210001000180") //
                .put("wmv", "3026b2758e66cf11a6d9") //wmv与asf相同
                .put("wav", "524946464694c9015741") //Wave (wav)
                .put("avi", "52494646d07d60074156")
                .put("mid", "4d546864000000060001") //MIDI (mid)
                .build();
    }

    private FileExtUtils() {
    }

    private final static Map<String, String> FILE_TYPE_MAP;

    static {
        //初始化文件类型信息
        FILE_TYPE_MAP = MapUtil.builder(MapUtil.<String, String>newHashMap())
                .put("ffd8ffe000104a464946", "jpg") //JPEG (jpg)
                .put("89504e470d0a1a0a0000", "png") //PNG (png)
                .put("47494638396126026f01", "gif") //GIF (gif)
                .put("49492a00227105008037", "tif") //TIFF (tif)
                .put("424d228c010000000000", "bmp") //16色位图(bmp)
                .put("424d8240090000000000", "bmp") //24位位图(bmp)
                .put("424d8e1b030000000000", "bmp") //256色位图(bmp)
                .put("41433130313500000000", "dwg") //CAD (dwg)
                .put("3c21444f435459504520", "html") //HTML (html)
                .put("3c21646f637479706520", "htm") //HTM (htm)
                .put("48544d4c207b0d0a0942", "css") //css
                .put("696b2e71623d696b2e71", "js") //js
                .put("7b5c727466315c616e73", "rtf") //Rich Text Format (rtf)
                .put("38425053000100000000", "psd") //Photoshop (psd)
                .put("46726f6d3a203d3f6762", "eml") //Email [Outlook Express 6] (eml)
                .put("d0cf11e0a1b11ae10000", "doc") //MS Excel 注意：word、msi 和 excel的文件头一样
                .put("d0cf11e0a1b11ae10000", "vsd") //Visio 绘图
                .put("5374616E64617264204A", "mdb") //MS Access (mdb)
                .put("252150532D41646F6265", "ps")
                .put("255044462d312e360d25", "pdf") //Adobe Acrobat (pdf)
                .put("2e524d46000000120001", "rmvb") //rmvb/rm相同
                .put("464c5601050000000900", "flv") //flv与f4v相同
                .put("00000020667479706973", "mp4")
                .put("49443303000000000f76", "mp3")
                .put("000001ba210001000180", "mpg") //
                .put("3026b2758e66cf11a6d9", "wmv") //wmv与asf相同
                .put("524946464694c9015741", "wav") //Wave (wav)
                .put("52494646d07d60074156", "avi")
                .put("4d546864000000060001", "mid") //MIDI (mid)
                .put("504b0304140000000800", "zip")
                .put("526172211a0700cf9073", "rar")
                .put("235468697320636f6e66", "ini")
                .put("504b03040a0000000000", "jar")
                .put("4d5a9000030000000400", "exe")//可执行文件
                .put("3c25402070616765206c", "jsp")//jsp文件
                .put("4d616e69666573742d56", "mf")//MF文件
                .put("3c3f786d6c2076657273", "xml")//xml文件
                .put("efbbbf2f2a0d0a53514c", "sql")//xml文件
                .put("7061636b616765207765", "java")//java文件
                .put("406563686f206f66660d", "bat")//bat文件
                .put("1f8b0800000000000000", "gz")//gz文件
                .put("6c6f67346a2e726f6f74", "properties")//bat文件
                .put("cafebabe0000002e0041", "class")//bat文件
                .put("49545346030000006000", "chm")//bat文件
                .put("04000000010000001300", "mxp")//bat文件
                .put("504b0304140006000800", "docx")//docx文件
                .put("d0cf11e0a1b11ae10000", "wps")//WPS文字wps、表格et、演示dps都是一样的
                .put("6431303a637265617465", "torrent")
                .put("494d4b48010100000200", "264")

                .put("6D6F6F76", "mov") //Quicktime (mov)
                .put("FF575043", "wpd") //WordPerfect (wpd)
                .put("CFAD12FEC5FD746F", "dbx") //Outlook Express (dbx)
                .put("2142444E", "pst") //Outlook (pst)
                .put("AC9EBD8F", "qdf") //Quicken (qdf)
                .put("E3828596", "pwl") //Windows Password (pwl)
                .put("2E7261FD", "ram") //Real Audio (ram)
                .build();
    }


    /**
     * 得到上传文件的文件头
     *
     * @param src
     * @return
     */
    private static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (null == src || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    /**
     * 获取文件类型
     *
     * @param file
     * @return
     */
    public static String getFileType(File file) {
        String res = null;
        try (FileInputStream fis = new FileInputStream(file)) {
            //获取文件头的前六位
            byte[] b = new byte[3];
            fis.read(b, 0, b.length);
            String fileCode = bytesToHexString(b);

            for (Map.Entry<String, String> keyIter : FILE_TYPE_MAP.entrySet()) {
                String key = keyIter.getKey();
                if (key.toLowerCase().startsWith(fileCode.toLowerCase()) || fileCode.toLowerCase().startsWith(key.toLowerCase())) {
                    res = FILE_TYPE_MAP.get(key);
                    break;
                }
            }
            log.info("文件头:" + fileCode + "-----文件类型:" + res);
        } catch (IOException ex) {
            ex.printStackTrace();
        }
        return res;
    }


    /**
     * 获取文件扩展名
     *
     * @param filename
     * @return
     */
    public static String getExtend(String filename) {
        return getExtend(filename, "");
    }

    /**
     * 获取文件扩展名
     *
     * @param filename
     * @return
     */
    public static String getExtend(String filename, String defExt) {
        if ((filename != null) && (filename.length() > 0)) {
            int i = filename.lastIndexOf('.');

            if ((i > 0) && (i < (filename.length() - 1))) {
                return (filename.substring(i + 1)).toLowerCase();
            }
        }
        return defExt.toLowerCase();
    }

    public static void copy(byte in[], File out) throws IOException {
        ByteArrayInputStream inStream = new ByteArrayInputStream(in);
        OutputStream outStream = new BufferedOutputStream(new FileOutputStream(out));
        copy(((InputStream) (inStream)), outStream);
    }

    public static int copy(InputStream in, OutputStream out) throws IOException {
        int byteCount = 0;
        byte buffer[] = new byte[4096];
        for (int bytesRead = -1; (bytesRead = in.read(buffer)) != -1; ) {
            out.write(buffer, 0, bytesRead);
            byteCount += bytesRead;
        }

        out.flush();
        return byteCount;
    }

    /**
     * 获取真实文件类型
     *
     * @param data 文件字节
     * @param ext  文件后缀
     * @return
     */
    public static boolean checkRealExtend(byte[] data, String ext) {
        if (!IS_VALIDATE_BYTE) {
            // 只jiao校验后缀
            for (String s : FILE_EXT_HEX.keySet()) {
                if (StringUtils.equalsIgnoreCase(s, ext)) {
                    return true;
                }
            }
            return false;
        }
        if (data == null) {
            log.info("data is null..................");
            return false;
        }
        StringBuilder sb = new StringBuilder();
        if (StringUtils.equalsIgnoreCase(ext, "svg")) {
            //获取文件头的前32位
            for (int i = 0; i < 32; i++) {
                sb.append(Integer.toHexString(data[i] >> 4 & 0xF));
                sb.append(Integer.toHexString(data[i] & 0xF));
            }
            // 是否包含<svg 标签的 HEX值
            if (!StringUtils.containsIgnoreCase(sb.toString(), "3C737667")) {
                return false;
            }
        } else {
            String hex = FILE_EXT_HEX.get(ext.toLowerCase());
            log.info("hex..................[{}]", hex);
            if (StringUtils.isBlank(hex)) {
                return false;
            }
            int length = hex.length() / 2;
            if (data.length < length) {
                return false;
            }
            for (int i = 0; i < length; i++) {
                sb.append(Integer.toHexString(data[i] >> 4 & 0xF));
                sb.append(Integer.toHexString(data[i] & 0xF));
            }
            log.info(hex);
            log.info("原文件内容" + sb.toString());
            if (!hex.equalsIgnoreCase(sb.toString())) {
                return false;
            }
        }
        return true;
    }

    /**
     * 获取文件类型 01：图片，02：文档
     *
     * @param originalFilename
     * @return
     */
    public static String getFileType(String originalFilename) {
        String fileType = "02";
        String extend = getExtend(originalFilename);
        boolean b = "jpg".equalsIgnoreCase(extend) || "jpeg".equalsIgnoreCase(extend) ||
                "jpe".equalsIgnoreCase(extend) || "gif".equalsIgnoreCase(extend) ||
                "png".equalsIgnoreCase(extend);
        if (b) {
            fileType = "01";
        }
        return fileType;
    }

    /**
     * MultipartFile 转 File
     *
     * @param file
     * @throws Exception
     */
    public static File multipartFileToFile(MultipartFile file) throws Exception {
        File toFile = null;
        if (!"".equals(file) || file.getSize() > 0) {
            InputStream ins = file.getInputStream();
            toFile = FileUtils.customFileByPath(file.getOriginalFilename());
            inputStreamToFile(ins, toFile);
            ins.close();
        }
        return toFile;
    }

    /**
     * 将附件下载到本地
     *
     * @param ins
     * @param file
     */
    public static void inputStreamToFile(InputStream ins, File file) {
        try (OutputStream os = new FileOutputStream(file);) {
            int bytesRead = 0;
            byte[] buffer = new byte[8192];
            while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            //os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
            log.info("将附件下载到本地报错,错误信息: {}", e);
        }
    }



    /**
     * 删除本地临时文件
     *
     * @param file
     */
    public static void deleteTempFile(File file) {
        if (file != null) {
            File del = new File(file.toURI());
            del.delete();
        }
    }
}
