package cc.winboll.studio.powerbell.utils;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import cc.winboll.studio.libappbase.LogUtils;

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import android.content.Context;
import android.net.Uri;

/**
 * 文件操作工具类
 * 功能：文件读写、复制、图片转换、文件名处理等常用文件操作
 * 适配：Java 7+，支持Android全版本
 * 注意：调用文件操作前需确保已获取存储权限（Android 6.0+ 需动态申请）
 */
public class FileUtils {

    /** 日志标签 */
    public static final String TAG = "FileUtils";
    /** 读取文件默认缓冲区大小（10KB） */
    private static final int BUFFER_SIZE = 10240;
    /** 最大读取文件大小（1GB），防止OOM */
    private static final long MAX_READ_FILE_SIZE = 1024 * 1024 * 1024;

    // ====================================== 文件读取相关 ======================================

    /**
     * 读取文件内容并转为字符串
     * @param filePath 文件绝对路径（非空）
     * @return 文件内容字符串
     * @throws IOException 异常：文件不存在、文件过大、读取失败等
     */
    public static String readFileAsString(String filePath) throws IOException {
        // 1. 校验文件合法性
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在：" + filePath);
        }
        if (file.length() > MAX_READ_FILE_SIZE) {
            throw new IOException("文件过大（超过1GB），禁止读取：" + filePath);
        }

        // 2. 读取文件内容（使用StringBuilder高效拼接）
        StringBuilder sb = new StringBuilder((int) file.length());
        try (FileInputStream fis = new FileInputStream(file)) {
            byte[] buffer = new byte[BUFFER_SIZE];
            int readLen;
            // 循环读取缓冲区，避免一次性读取大文件导致OOM
            while ((readLen = fis.read(buffer)) > 0) {
                sb.append(new String(buffer, 0, readLen));
            }
        }
        return sb.toString();
    }

    /**
     * 读取文件内容并转为byte数组（适用于二进制文件：图片、音频等）
     * @param filePath 文件绝对路径（非空）
     * @return 文件内容byte数组
     * @throws IOException 异常：文件不存在、读取失败等
     */
    public static byte[] readFileByBytes(String filePath) throws IOException {
        // 1. 校验文件合法性
        File file = new File(filePath);
        if (!file.exists()) {
            throw new FileNotFoundException("文件不存在：" + filePath);
        }

        // 2. 缓冲流读取（高效，减少IO次数）
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream((int) file.length());
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file))) {

            byte[] buffer = new byte[BUFFER_SIZE];
            int readLen;
            while ((readLen = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, readLen);
            }
            bos.flush();
            return bos.toByteArray();
        }
    }

    // ====================================== 文件复制相关 ======================================

    /**
     * 基于FileChannel复制文件（高效，适用于大文件复制）
     * @param source 源文件（非空，必须存在）
     * @param dest 目标文件（非空，父目录会自动创建）
     * @throws IOException 异常：源文件不存在、复制失败等
     */
    public static void copyFileUsingFileChannels(File source, File dest) throws IOException {
        // 1. 校验源文件合法性
        if (!source.exists() || !source.isFile()) {
            throw new FileNotFoundException("源文件不存在或不是文件：" + source.getAbsolutePath());
        }

        // 2. 创建目标文件父目录
        if (!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }

        // 3. 通道复制（try-with-resources 自动关闭通道，无需手动关闭）
        try (FileChannel inputChannel = new FileInputStream(source).getChannel();
		FileChannel outputChannel = new FileOutputStream(dest).getChannel()) {
            // 从输入通道复制到输出通道（高效，底层优化）
            outputChannel.transferFrom(inputChannel, 0, inputChannel.size());
            LogUtils.d(TAG, "文件复制成功（FileChannel）：" + source.getAbsolutePath() + " → " + dest.getAbsolutePath());
        }
    }

    /**
     * 简化版文件复制（基于NIO Files工具类，代码简洁，适用于中小文件）
     * @param oldFile 源文件（非空，必须存在）
     * @param newFile 目标文件（非空，父目录会自动创建）
     * @return 复制结果：true-成功，false-失败
     */
    public static boolean copyFile(File oldFile, File newFile) {
        // 1. 校验源文件合法性
        if (oldFile == null || !oldFile.exists() || !oldFile.isFile()) {
            LogUtils.e(TAG, "源文件无效：" + (oldFile != null ? oldFile.getAbsolutePath() : "null"));
            return false;
        }

        // 2. 创建目标文件父目录
        if (!newFile.getParentFile().exists()) {
            newFile.getParentFile().mkdirs();
        }

        // 3. 复制文件（覆盖已有目标文件）
        try {
            Path sourcePath = Paths.get(oldFile.getPath());
            Path destPath = Paths.get(newFile.getPath());
            // 先删除已有目标文件（避免覆盖失败）
            if (newFile.exists()) {
                newFile.delete();
            }
            Files.copy(sourcePath, destPath);
            LogUtils.d(TAG, "文件复制成功（Files）：" + oldFile.getAbsolutePath() + " → " + newFile.getAbsolutePath());
            return true;
        } catch (Exception e) {
            LogUtils.e(TAG, "文件复制失败：" + e.getMessage(), e);
            return false;
        }
    }

    // ====================================== 图片文件相关 ======================================

    /**
     * 从文件路径获取BitmapDrawable（适用于Android图片显示）
     * @param path 图片文件绝对路径（非空）
     * @return BitmapDrawable 图片对象（文件不存在/读取失败返回null）
     * @throws IOException 异常：文件读取IO错误
     */
    public static BitmapDrawable getImageDrawable(String path) throws IOException {
        // 1. 校验文件合法性
        File file = new File(path);
        if (!file.exists() || !file.isFile()) {
            LogUtils.e(TAG, "图片文件不存在：" + path);
            return null;
        }

        // 2. 读取文件并转为BitmapDrawable（缓冲流读取，减少内存占用）
        try (InputStream is = new FileInputStream(file);
		ByteArrayOutputStream bos = new ByteArrayOutputStream()) {

            byte[] buffer = new byte[BUFFER_SIZE];
            int readLen;
            while ((readLen = is.read(buffer)) != -1) {
                bos.write(buffer, 0, readLen);
            }

            // 3. 生成Bitmap并包装为BitmapDrawable
            byte[] imageBytes = bos.toByteArray();
            Bitmap bitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
            return new BitmapDrawable(bitmap);
        }
    }

    // ====================================== 文件名处理相关 ======================================

    /**
     * 截取文件后缀名（兼容多 "." 场景，如"image.2025.png" → ".png"）
     * @param file 目标文件（可为null）
     * @return 文件后缀名：带点（如".jpg"），无后缀/文件无效返回空字符串
     */
    public static String getFileSuffixWithMultiDot(File file) {
        // 1. 校验文件合法性
        if (file == null || !file.isFile()) {
            return "";
        }

        // 2. 提取文件名并查找最后一个 "."
        String fileName = file.getName();
        int lastDotIndex = fileName.lastIndexOf(".");

        // 3. 校验后缀合法性（排除无后缀、以点结尾、后缀过长的异常文件）
        if (lastDotIndex == -1 // 无 "."
			|| lastDotIndex == fileName.length() - 1 // 以 "." 结尾（如".gitignore"）
			|| (fileName.length() - lastDotIndex) > 5) { // 后缀长度超过5（异常文件名）
            return "";
        }

        // 4. 返回小写后缀（统一格式，避免大小写不一致问题）
        return fileName.substring(lastDotIndex).toLowerCase();
    }

    /**
     * 生成唯一文件名（优化版：唯一、合法、简洁）
     * 生成规则：UUID(去掉"-") + "_" + 时间戳 + 原文件后缀
     * @param refFile 参考文件（用于提取后缀名，可为null）
     * @return 唯一文件名（如"a1b2c3d4e5f6_1730000000000.jpg"，无后缀则不带点）
     */
    public static String createUniqueFileName(File refFile) {
        // 1. 获取参考文件的后缀名（自动容错null/无效文件）
        String suffix = getFileSuffixWithMultiDot(refFile);

        // 2. 生成唯一标识（UUID确保全局唯一，时间戳进一步降低重复概率）
        String uniqueId = UUID.randomUUID().toString().replace("-", ""); // 去掉"-"简化文件名
        long timeStamp = System.currentTimeMillis();

        // 3. 拼接文件名（分场景处理，避免多余点）
        if (suffix.isEmpty()) {
            // 无后缀：唯一ID + 时间戳
            return String.format("%s_%d", uniqueId, timeStamp);
        } else {
            // 有后缀：唯一ID + 时间戳 + 后缀（无多余点）
            return String.format("%s_%d%s", uniqueId, timeStamp, suffix);
        }
    }

	/**
	 * 复制输入流到文件（兼容Uri解析失败场景）
	 */
	public static void copyStreamToFile(InputStream inputStream, File file) throws IOException {
		if (inputStream == null || file == null) {
			throw new IllegalArgumentException("InputStream或File不能为空");
		}
		File parentDir = file.getParentFile();
		if (!parentDir.exists() && !parentDir.mkdirs()) {
			throw new IOException("无法创建父目录：" + parentDir.getAbsolutePath());
		}
		try {
			OutputStream outputStream = new FileOutputStream(file);
			byte[] buffer = new byte[1024];
			int length;
			while ((length = inputStream.read(buffer)) != -1) {
				outputStream.write(buffer, 0, length);
			}
			outputStream.flush();
		} finally {
			try {
				inputStream.close();
			} catch (IOException e) {
				LogUtils.e("FileUtils", "关闭输入流失败：" + e.getMessage());
			}
		}
	}
	
	public static boolean isFileExists(String path) {
		File file = new File(path);
		return file.exists();
	}
	
	/**
	 * 获取文件后缀（不带点，忽略大小写，适配空文件名/无后缀场景）
	 * @param file 目标文件
	 * @return 后缀字符串（无后缀返回空字符串，非空统一小写）
	 */
	public static String getFileSuffix(File file) {
		if (file == null || file.getName().isEmpty()) {
			return ""; // 空文件/空文件名，返回空
		}
		String fileName = file.getName();
		int lastDotIndex = fileName.lastIndexOf(".");
		// 无后缀（没有点，或点在开头/结尾）
		if (lastDotIndex == -1 || lastDotIndex == 0 || lastDotIndex == fileName.length() - 1) {
			return "";
		}
		// 截取后缀并转小写（统一格式，避免 PNG/png 差异）
		return fileName.substring(lastDotIndex + 1).toLowerCase();
	}
}

