package com.bcxin.backend.domain.utils;

import cn.hutool.core.codec.Base64;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.thread.ThreadUtil;
import com.bcxin.backend.domain.utils.ftp.FtpConnection;
import com.bcxin.backend.domain.utils.ftp.FtpFactory;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.stream.FileImageInputStream;
import java.io.*;
import java.net.URL;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 有关文件处理的工具类
 * @author       liandi
 * @see          [相关类，可选、也可多条，对于重要的类或接口建议注释]
 * @since        esign, 2017年10月24日
 */
public final class FileUtils
{
    private static final Logger logger = LoggerFactory.getLogger(FileUtils.class);
    
    /**
     * 创建目录，如果目录已经存在，则将会返回false
     * @author       liandi
     * @since        esign, 2017年10月24日
     * @param file
     * @return 
     */
    public static boolean mkdirs(File file) {
        if (null == file) return false;

        if (file.exists()) return false;

        return file.mkdirs();
    }
    
    /**
     * 创建目录，如果目录已经存在，则将会返回false
     * @author       liandi
     * @since        esign, 2017年10月24日
     * @param directory
     * @return
     */
    public static boolean mkdirs(String directory)
    {
        if(StringUtils.isBlank(directory)) return false;
        
        return mkdirs(new File(directory));
    }
    

    
    /**
     * 文件是否存在
     * @author       liandi
     * @since        esign, 2017年12月18日
     * @param fileName   文件的绝对路径
     * @return
     */
    public static boolean exists(String fileName)
    {
        if (StringUtils.isBlank(fileName)) return false;
        
        File file = new File(fileName);
        
        return file.exists();
    }


    /**
     * <b> 获取ftp目录下所有最近5分钟内生成的文件的文件名，返回文件名列表 </b>
     * @author ZXF
     * @create 2024/11/27 0027 8:44
     * @version
     * @注意事项 </b>
     */
    public static List<File> filenames(String path, String keyword) {
        List<File> matchedFiles = null;
        List<File> recentlyMatchFiles = null;
        File folder = new File(path);
        if (folder == null) {
            return Collections.EMPTY_LIST;
        }
        File[] subFiles = folder.listFiles();
        if (subFiles == null) {
            return Collections.EMPTY_LIST;
        }

        StringBuilder trace = new StringBuilder();
        try {
            trace.append(String.format("Obtaining normal files:%s;", keyword));
            matchedFiles =
                    Arrays.stream(subFiles)
                            .filter(ii -> ii.isFile() && (StringUtils.isEmpty(keyword) || ii.getName().startsWith(keyword)))
                            .collect(Collectors.toList());

            trace.append(String.format("size=:%s;", (matchedFiles == null ? "0" : matchedFiles.size())));
            recentlyMatchFiles =
                    matchedFiles.stream().sorted((f1, f2) -> {
                                try {
                                    return Long.compare(f2.lastModified(), f1.lastModified());
                                } catch (Exception ex) {
                                    logger.error("比较文件的时候发生异常:{}={}-{}={}", f1.getName(), f1.lastModified(), f2.getName(), f2.lastModified());
                                    return 0;
                                }
                            })
                            .limit(100).collect(Collectors.toList());

            logger.error("Filenames: success in getting files({})(original={},size={})", keyword, subFiles.length, matchedFiles.size());

            return recentlyMatchFiles;
        } catch (Exception ex) {
            logger.error("failed to getting files({}); track={}", keyword, trace, ex);
            throw ex;
        }
    }

    //使用hutool 文件工具类 实现传入文件路径和文件名、文件文本内容 生成文件
    public static void writeFile(String filePath, String fileName, String content) {
        File file = new File(filePath + File.separator + fileName);
        if (!file.exists()) {
            FileUtils.touch(file);
        }

        FileUtil.writeString(content, file, "UTF-8");
    }

    /**
     * <b> 远程地址转base64 </b>
     * @author ZXF
     * @create 2025/01/08 0008 15:18
     * @version
     * @注意事项 </b>
     */
    public static String urlToBase64(HttpClient httpClient,String url) {
        // 使用Java的IO流来读取远程文件内容
        /*
        try (InputStream inputStream = new URL(url).openStream()) {
            // 读取文件内容
            byte[] bytes = IoUtil.readBytes(inputStream);
            // 转换为 Base64 字符串
            return Base64.encode(bytes);
        } catch (Exception e) {
            logger.error("urlToBase64({})", url, e);
        }
        return "";

         */
        try {
            HttpGet httpGet = new HttpGet(url);
            HttpResponse httpResponse = httpClient.execute(httpGet);

            try (InputStream inputStream = httpResponse.getEntity().getContent()) {
                byte[] bytes = IoUtil.readBytes(inputStream);

                return Base64.encode(bytes);
            }
        } catch (Exception ex) {
            logger.error("urlToBase64({})", url, ex);

            throw new RuntimeException(String.format("urlToBase64(%s)", url), ex);
        }
    }

    public static String fileToBase64(String filePath) {
        try (InputStream inputStream = new FileInputStream(filePath)) {
            // 读取文件内容
            byte[] bytes = IOUtils.toByteArray(inputStream);
            // 转换为 Base64 字符串
            return Base64.encode(bytes);
        }catch (Exception e){
            logger.error("fileToBase64({})",filePath,e);
        }
        return "";
    }

    private static AtomicInteger fileLockCount = new AtomicInteger(0);
    public static void touch(File file) {
        try {
            while (fileLockCount.get() > 500) {
                ThreadUtil.sleep(500);
                logger.error("Not Allowed to touch file={} count={}", file, fileLockCount.get());
            }

            fileLockCount.incrementAndGet();
            FileUtil.touch(file);
        } finally {
            fileLockCount.decrementAndGet();
        }
    }
}
