package dev.bytevibe.hyperpoint;

import com.google.gson.*;
import javafx.scene.paint.Color;

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

/**
 * JSON序列化工具，用于将演示文稿保存和加载为JSON格式
 */
public class JsonSerializationUtil {
    private static final Gson gson = new GsonBuilder()
            .setPrettyPrinting()
            .create();

    /**
     * 将演示文稿保存为JSON文件
     */
    public static void saveToJson(Presentation presentation, File file) throws IOException {
        JsonObject root = new JsonObject();

        // 保存演示文稿基本信息
        root.addProperty("name", presentation.getName());

        // 保存所有幻灯片
        JsonArray slidesArray = new JsonArray();
        for (Slide slide : presentation.getSlides()) {
            slidesArray.add(serializeSlide(slide));
        }
        root.add("slides", slidesArray);

        // 写入文件
        try (FileWriter writer = new FileWriter(file)) {
            gson.toJson(root, writer);
        }
    }

    /**
     * 从JSON文件加载演示文稿
     */
    public static Presentation loadFromJson(File file) throws IOException {
        // 读取文件
        String jsonContent;
        try (FileReader reader = new FileReader(file)) {
            jsonContent = new String(new byte[]{});
            StringBuilder sb = new StringBuilder();
            int c;
            while ((c = reader.read()) != -1) {
                sb.append((char) c);
            }
            jsonContent = sb.toString();
        }

        // 解析JSON
        JsonObject root = JsonParser.parseString(jsonContent).getAsJsonObject();
        String name = root.get("name").getAsString();
        Presentation presentation = new Presentation(name);

        // 加载所有幻灯片
        JsonArray slidesArray = root.getAsJsonArray("slides");
        for (JsonElement slideElement : slidesArray) {
            presentation.addSlide(deserializeSlide(slideElement.getAsJsonObject()));
        }

        return presentation;
    }

    /**
     * 序列化幻灯片
     */
    private static JsonObject serializeSlide(Slide slide) {
        JsonObject slideObj = new JsonObject();
        slideObj.addProperty("id", slide.getId());
        slideObj.addProperty("name", slide.getName());

        // 序列化所有页面
        JsonArray pagesArray = new JsonArray();
        for (SlidePage page : slide.getPages()) {
            pagesArray.add(serializePage(page));
        }
        slideObj.add("pages", pagesArray);

        return slideObj;
    }

    /**
     * 反序列化幻灯片
     */
    private static Slide deserializeSlide(JsonObject slideObj) {
        String name = slideObj.get("name").getAsString();
        Slide slide = new Slide(name);

        // 清除默认页面
        slide.getPages().clear();

        // 加载所有页面
        JsonArray pagesArray = slideObj.getAsJsonArray("pages");
        for (JsonElement pageElement : pagesArray) {
            slide.getPages().add(deserializePage(pageElement.getAsJsonObject()));
        }

        return slide;
    }

    /**
     * 序列化页面
     */
    private static JsonObject serializePage(SlidePage page) {
        JsonObject pageObj = new JsonObject();
        pageObj.addProperty("id", page.getId());
        pageObj.addProperty("title", page.getTitle());
        pageObj.addProperty("content", page.getContent());

        // 序列化页面中的所有可绘制对象
        JsonArray objectsArray = new JsonArray();
        for (DrawableObject obj : page.getPageContent().getDrawableObjects()) {
            objectsArray.add(serializeDrawableObject(obj));
        }
        pageObj.add("objects", objectsArray);

        return pageObj;
    }

    /**
     * 反序列化页面
     */
    private static SlidePage deserializePage(JsonObject pageObj) {
        String id = pageObj.get("id").getAsString();
        String title = pageObj.get("title").getAsString();
        String content = pageObj.has("content") ? pageObj.get("content").getAsString() : "";

        SlidePage page = new SlidePage(title);
        page.setId(id);
        page.setContent(content);

        // 加载所有可绘制对象
        if (pageObj.has("objects")) {
            JsonArray objectsArray = pageObj.getAsJsonArray("objects");
            for (JsonElement objElement : objectsArray) {
                DrawableObject obj = deserializeDrawableObject(objElement.getAsJsonObject());
                if (obj != null) {
                    page.getPageContent().addObject(obj);
                }
            }
        }

        return page;
    }

    /**
     * 序列化可绘制对象
     */
    private static JsonObject serializeDrawableObject(DrawableObject obj) {
        JsonObject objJson = new JsonObject();

        objJson.addProperty("id", obj.getId());
        objJson.addProperty("x", obj.getX());
        objJson.addProperty("y", obj.getY());
        objJson.addProperty("width", obj.getWidth());
        objJson.addProperty("height", obj.getHeight());
        objJson.addProperty("type", obj.getTypeName());

        if (obj instanceof TextObject) {
            TextObject textObj = (TextObject) obj;
            objJson.addProperty("text", textObj.getText());
            objJson.addProperty("fontFamily", textObj.getFontFamily());
            objJson.addProperty("fontSize", textObj.getFontSize());
            objJson.addProperty("fontStyle", textObj.getFontStyle());
            objJson.addProperty("textColor", textObj.getTextColor());

        } else if (obj instanceof ShapeObject) {
            ShapeObject shapeObj = (ShapeObject) obj;
            objJson.addProperty("shapeType", shapeObj.getShapeType().name());
            objJson.addProperty("fillColor", shapeObj.getFillColor());
            objJson.addProperty("strokeColor", shapeObj.getStrokeColor());
            objJson.addProperty("strokeWidth", shapeObj.getStrokeWidth());

        } else if (obj instanceof ImageObject) {
            ImageObject imgObj = (ImageObject) obj;
            objJson.addProperty("imagePath", imgObj.getImagePath());
        }

        return objJson;
    }

    /**
     * 反序列化可绘制对象
     */
    private static DrawableObject deserializeDrawableObject(JsonObject objJson) {
        String type = objJson.get("type").getAsString();
        double x = objJson.get("x").getAsDouble();
        double y = objJson.get("y").getAsDouble();
        double width = objJson.get("width").getAsDouble();
        double height = objJson.get("height").getAsDouble();
        String id = objJson.get("id").getAsString();

        DrawableObject obj = null;

        if (type.equals("Text")) {
            String text = objJson.get("text").getAsString();
            obj = new TextObject(x, y, text);
            obj.setWidth(width);
            obj.setHeight(height);

            TextObject textObj = (TextObject) obj;
            if (objJson.has("fontFamily")) {
                textObj.setFontFamily(objJson.get("fontFamily").getAsString());
            }
            if (objJson.has("fontSize")) {
                textObj.setFontSize(objJson.get("fontSize").getAsDouble());
            }
            if (objJson.has("fontStyle")) {
                textObj.setFontStyle(objJson.get("fontStyle").getAsString());
            }
            if (objJson.has("textColor")) {
                textObj.setTextColor(objJson.get("textColor").getAsString());
            }

        } else if (type.startsWith("Shape_")) {
            String shapeTypeStr = type.replace("Shape_", "");
            ShapeObject.ShapeType shapeType = ShapeObject.ShapeType.valueOf(shapeTypeStr);
            obj = new ShapeObject(x, y, width, height, shapeType);

            ShapeObject shapeObj = (ShapeObject) obj;
            if (objJson.has("fillColor")) {
                shapeObj.setFillColor(objJson.get("fillColor").getAsString());
            }
            if (objJson.has("strokeColor")) {
                shapeObj.setStrokeColor(objJson.get("strokeColor").getAsString());
            }
            if (objJson.has("strokeWidth")) {
                shapeObj.setStrokeWidth(objJson.get("strokeWidth").getAsDouble());
            }

        } else if (type.equals("Image")) {
            String imagePath = objJson.get("imagePath").getAsString();
            obj = new ImageObject(x, y, width, height, imagePath);
        }

        if (obj != null) {
            obj.setId(id);
        }

        return obj;
    }
}

