package com.bonus.common.core.utils;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.w3c.dom.Document;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.Map;
import java.util.Properties;

/**
 * 文件操作工具类，提供对常见文件格式的读写操作。
 * 支持的文件格式包括：Properties、YML、XML、JSON、CIME、SVG。
 */
public class ConfigFileUtils {

    /**
     * 读取文件内容为字符串。
     *
     * @param file 需要读取的文件
     * @return 文件内容的字符串表示
     * @throws IOException 如果读取文件时发生错误
     */
    public static String readFileToString(File file) throws IOException {
        return new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8);
    }

    /**
     * 将字符串写入文件。
     *
     * @param file    目标文件
     * @param content 要写入文件的内容
     * @throws IOException 如果写入文件时发生错误
     */
    public static void writeStringToFile(File file, String content) throws IOException {
        Files.write(file.toPath(), content.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * 从 `.properties` 文件中读取属性。
     *
     * @param file 需要读取的 `.properties` 文件
     * @return 读取到的属性对象
     * @throws IOException 如果读取文件时发生错误
     */
    public static Properties readProperties(File file) throws IOException {
        Properties properties = new Properties();
        try (FileInputStream fis = new FileInputStream(file)) {
            properties.load(fis);
        }
        return properties;
    }

    /**
     * 将属性写入 `.properties` 文件。
     *
     * @param file       目标 `.properties` 文件
     * @param properties 要写入的属性对象
     * @throws IOException 如果写入文件时发生错误
     */
    public static void writeProperties(File file, Properties properties) throws IOException {
        try (FileOutputStream fos = new FileOutputStream(file)) {
            properties.store(fos, null);
        }
    }

    /**
     * 从 `.yml` 文件中读取 YAML 数据。
     *
     * @param file 需要读取的 `.yml` 文件
     * @return 读取到的 YAML 数据，作为 `Map<String, Object>` 对象
     * @throws IOException 如果读取文件时发生错误
     */
    public static Map<String, Object> readYml(File file) throws IOException {
        Yaml yaml = new Yaml();
        try (FileInputStream fis = new FileInputStream(file)) {
            return yaml.load(fis);
        }
    }

    /**
     * 将数据写入 `.yml` 文件。
     *
     * @param file 目标 `.yml` 文件
     * @param data 要写入的数据，作为 `Map<String, Object>` 对象
     * @throws IOException 如果写入文件时发生错误
     */
    public static void writeYml(File file, Map<String, Object> data) throws IOException {
        // 设置 YAML 的格式化选项
        DumperOptions options = new DumperOptions();
        options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); // 使用块格式而不是流格式
        options.setIndent(2); // 设置缩进
        options.setPrettyFlow(true); // 保持格式的美观
        options.setDefaultScalarStyle(DumperOptions.ScalarStyle.PLAIN); // 纯文本格式

        // 初始化 YAML 实例
        Yaml yaml = new Yaml(options);
        try (FileOutputStream fos = new FileOutputStream(file)) {
            yaml.dump(data, new OutputStreamWriter(fos, StandardCharsets.UTF_8));
        }
    }

    /**
     * 从 `.xml` 文件中读取 XML 数据。
     *
     * @param file 需要读取的 `.xml` 文件
     * @return 读取到的 XML 文档对象
     * @throws Exception 如果解析文件时发生错误
     */
    public static Document readXml(File file) throws Exception {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        try (FileInputStream fis = new FileInputStream(file)) {
            return builder.parse(fis);
        }
    }

    /**
     * 将 XML 数据写入 `.xml` 文件。
     *
     * @param file     目标 `.xml` 文件
     * @param document 要写入的 XML 文档对象
     * @throws Exception 如果写入文件时发生错误
     */
    public static void writeXml(File file, Document document) throws Exception {
        TransformerFactory transformerFactory = TransformerFactory.newInstance();
        Transformer transformer = transformerFactory.newTransformer();
        transformer.setOutputProperty(OutputKeys.INDENT, "yes");
        DOMSource source = new DOMSource(document);
        try (FileOutputStream fos = new FileOutputStream(file)) {
            StreamResult result = new StreamResult(fos);
            transformer.transform(source, result);
        }
    }

    /**
     * 从 `.json` 文件中读取 JSON 数据并将其转换为指定的 Java 对象。
     *
     * @param file      需要读取的 `.json` 文件
     * @param valueType 目标 Java 对象的类
     * @param <T>       目标 Java 对象的类型
     * @return 读取到的 Java 对象
     * @throws IOException 如果读取文件时发生错误
     */
    public static <T> T readJson(File file, Class<T> valueType) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        try (FileInputStream fis = new FileInputStream(file)) {
            return mapper.readValue(fis, valueType);
        }
    }

    /**
     * 将数据写入 `.json` 文件。
     *
     * @param file  目标 `.json` 文件
     * @param value 要写入的数据，作为 Java 对象
     * @param <T>   数据的类型
     * @throws IOException 如果写入文件时发生错误
     */
    public static <T> void writeJson(File file, T value) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        try (FileOutputStream fos = new FileOutputStream(file)) {
            mapper.writeValue(fos, value);
        }
    }

    /**
     * 从 `.cime` 文件中读取内容。假设 CIME 是一种自定义的文本格式。
     *
     * @param file 需要读取的 `.cime` 文件
     * @return 读取到的文件内容
     * @throws IOException 如果读取文件时发生错误
     */
    public static String readCime(File file) throws IOException {
        return readFileToString(file);
    }

    /**
     * 将内容写入 `.cime` 文件。假设 CIME 是一种自定义的文本格式。
     *
     * @param file    目标 `.cime` 文件
     * @param content 要写入的内容
     * @throws IOException 如果写入文件时发生错误
     */
    public static void writeCime(File file, String content) throws IOException {
        writeStringToFile(file, content);
    }

    /**
     * 从 `.svg` 文件中读取内容。
     *
     * @param file 需要读取的 `.svg` 文件
     * @return 读取到的文件内容
     * @throws IOException 如果读取文件时发生错误
     */
    public static String readSvg(File file) throws IOException {
        return readFileToString(file);
    }

    /**
     * 将内容写入 `.svg` 文件。
     *
     * @param file    目标 `.svg` 文件
     * @param content 要写入的内容
     * @throws IOException 如果写入文件时发生错误
     */
    public static void writeSvg(File file, String content) throws IOException {
        writeStringToFile(file, content);
    }

    /**
     * 读取 `.txt` 文件的内容并将其转换为字符串。
     *
     * @param file 需要读取的 `.txt` 文件
     * @return 文件内容的字符串表示
     * @throws IOException 如果读取文件时发生错误
     */
    public static String readTxt(File file) throws IOException {
        return readFileToString(file);
    }

    /**
     * 将字符串内容写入 `.txt` 文件。
     *
     * @param file    目标 `.txt` 文件
     * @param content 要写入文件的内容
     * @throws IOException 如果写入文件时发生错误
     */
    public static void writeTxt(File file, String content) throws IOException {
        writeStringToFile(file, content);
    }

    /**
     * 从 `.properties` 文件中根据 key 读取属性值。
     *
     * @param file 需要读取的 `.properties` 文件
     * @param key  要获取的属性键
     * @return 属性值
     * @throws IOException 如果读取文件时发生错误
     */
    public static String readPropertyByKey(File file, String key) throws IOException {
        Properties properties = readProperties(file);
        return properties.getProperty(key);
    }

    /**
     * 从 `.yml` 文件中根据 key 读取属性值。
     *
     * @param file 需要读取的 `.yml` 文件
     * @param key  要获取的属性键
     * @return 属性值
     * @throws IOException 如果读取文件时发生错误
     */
    public static Object readYmlByKey(File file, String key) throws IOException {
        Map<String, Object> data = readYml(file);
        return getValueByKey(data, key);
    }

    /**
     * 从 `.json` 文件中根据 key 读取属性值。
     *
     * @param file 需要读取的 `.json` 文件
     * @param key  要获取的属性键
     * @return 属性值
     * @throws IOException 如果读取文件时发生错误
     */
    public static Object readJsonByKey(File file, String key) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        Map<String, Object> data = mapper.readValue(file, Map.class);
        return getValueByKey(data, key);
    }

    /**
     * 从嵌套 Map 中获取指定 key 的值。
     *
     * @param map Map 数据
     * @param key 要获取的属性键
     * @return 属性值
     */
    private static Object getValueByKey(Map<String, Object> map, String key) {
        String[] keys = key.split("\\.");
        Map<String, Object> currentMap = map;
        for (int i = 0; i < keys.length - 1; i++) {
            Object value = currentMap.get(keys[i]);
            if (value instanceof Map) {
                currentMap = (Map<String, Object>) value;
            } else {
                return null;
            }
        }
        return currentMap.get(keys[keys.length - 1]);
    }


}
