import { app, BrowserWindow, clipboard, ipcMain, nativeImage, nativeTheme, screen, shell } from "electron";
import { spawn } from "child_process";
import { AppConfig } from "../../../src/config";
import { CommonConfig } from "../../config/common";
import { WindowConfig } from "../../config/window";
import { isDev, isMac, platformArch, platformName, platformUUID, platformVersion } from "../../lib/env";
import { preloadDefault, rendererDistPath } from "../../lib/env-main";
import { getResourceRoot } from "../../lib/resource-path";
import { Page } from "../../page";
import { ConfigMain } from "../config/main";
import { AppRuntime } from "../env";
import { Events } from "../event/main";
import { Files } from "../file/main";
import Apps from "./index";
import { AppPosition } from "./lib/position";
import { makeLoading } from "./loading";
import { SetupMain } from "./setup";
import { makeToast } from "./toast";

const getWindowByName = (name?: string) => {
    if (!name || "main" === name) {
        return AppRuntime.mainWindow;
    }
    return AppRuntime.windows[name];
};

const getCurrentWindow = (window, e) => {
    let originWindow = BrowserWindow.fromWebContents(e.sender);
    // if (originWindow !== window) originWindow = detachInstance.getWindow();
    return originWindow;
};

const quit = () => {
    // @ts-ignore
    app.quitForce = true;
    app.quit();
};

ipcMain.handle("app:quit", () => {
    quit();
});

const restart = () => {
    app.relaunch();
};

ipcMain.handle("app:restart", () => {
    restart();
});

const windowMin = (name?: string) => {
    getWindowByName(name)?.minimize();
};

const windowMax = (name?: string) => {
    const win = getWindowByName(name);
    if (!win) {
        return;
    }
    if (win.isFullScreen()) {
        win.setFullScreen(false);
        win.unmaximize();
        win.center();
    } else if (win.isMaximized()) {
        win.unmaximize();
        win.center();
    } else {
        win.setMinimumSize(WindowConfig.minWidth, WindowConfig.minHeight);
        win.maximize();
    }
};

const windowSetSize = (
    name: string | null,
    width: number,
    height: number,
    option?: {
        includeMinimumSize: boolean;
        center: boolean;
    }
) => {
    width = parseInt(String(width));
    height = parseInt(String(height));
    // console.log('windowSetSize', name, width, height, option)
    const win = getWindowByName(name);
    if (!win) {
        return;
    }
    option = Object.assign(
        {
            includeMinimumSize: true,
            center: true,
        },
        option
    );
    if (option.includeMinimumSize) {
        win.setMinimumSize(width, height);
    }
    win.setSize(width, height);
    if (option.center) {
        win.center();
    }
};

ipcMain.handle("app:openExternal", (event, url: string) => {
    return shell.openExternal(url);
});
ipcMain.handle("app:openPath", (event, url: string) => {
    return shell.openPath(url);
});
ipcMain.handle("app:showItemInFolder", (event, url: string) => {
    return shell.showItemInFolder(url);
});

ipcMain.handle("app:getPreload", event => {
    let preload = preloadDefault;
    if (!preload.startsWith("file://")) {
        preload = `file://${preload}`;
    }
    return preload;
});

ipcMain.handle("window:min", (event, name: string) => {
    windowMin(name);
});
ipcMain.handle("window:max", (event, name: string) => {
    windowMax(name);
});
ipcMain.handle(
    "window:setSize",
    (
        event,
        name: string | null,
        width: number,
        height: number,
        option?: {
            includeMinimumSize: boolean;
            center: boolean;
        }
    ) => {
        windowSetSize(name, width, height, option);
    }
);

ipcMain.handle("window:close", (event, name: string) => {
    getWindowByName(name)?.close();
});

const windowOpen = async (
    name: string,
    option?: {
        singleton?: boolean;
        parent?: BrowserWindow;
        [key: string]: any;
    }
) => {
    name = name || "main";
    return Page.open(name, option);
};

ipcMain.handle("window:open", (event, name: string, option: any) => {
    return windowOpen(name, option);
});

ipcMain.handle("window:hide", (event, name: string) => {
    getWindowByName(name)?.hide();
    if (isMac) {
        app.dock.hide();
    }
});

ipcMain.handle(
    "window:move",
    (
        event,
        name: string | null,
        data: {
            mouseX: number;
            mouseY: number;
            width: number;
            height: number;
        }
    ) => {
        const { x, y } = screen.getCursorScreenPoint();
        const originWindow = getWindowByName(name);
        if (!originWindow) return;
        originWindow.setBounds({ x: x - data.mouseX, y: y - data.mouseY, width: data.width, height: data.height });
        AppPosition.set(name, x - data.mouseX, y - data.mouseY);
    }
);

const getClipboardText = () => {
    return clipboard.readText("clipboard");
};

ipcMain.handle("app:getClipboardText", event => {
    return getClipboardText();
});

const setClipboardText = (text: string) => {
    clipboard.writeText(text, "clipboard");
};

ipcMain.handle("app:setClipboardText", (event, text: string) => {
    setClipboardText(text);
});

const getClipboardImage = () => {
    const image = clipboard.readImage("clipboard");
    return image.isEmpty() ? "" : image.toDataURL();
};

ipcMain.handle("app:getClipboardImage", event => {
    return getClipboardImage();
});

const setClipboardImage = (image: string) => {
    const img = nativeImage.createFromDataURL(image);
    clipboard.writeImage(img, "clipboard");
};

ipcMain.handle("app:setClipboardImage", (event, image: string) => {
    setClipboardImage(image);
});

const isDarkMode = () => {
    if (!CommonConfig.darkModeEnable) {
        return false;
    }
    return nativeTheme.shouldUseDarkColors;
};

const shouldDarkMode = async () => {
    if (!CommonConfig.darkModeEnable) {
        return false;
    }
    const darkMode = (await ConfigMain.get("darkMode")) || "auto";
    if ("dark" === darkMode) {
        return true;
    } else if ("light" === darkMode) {
        return false;
    } else if ("auto" === darkMode) {
        return isDarkMode();
    }
    return false;
};

const defaultDarkModeBackgroundColor = async () => {
    if (await shouldDarkMode()) {
        return "#17171A";
    }
    return "#FFFFFF";
};

nativeTheme.on("updated", () => {
    Events.broadcast("DarkModeChange", { isDarkMode: isDarkMode() });
    AppsMain.defaultDarkModeBackgroundColor().then(color => {
        AppRuntime.mainWindow.setBackgroundColor(color)
    });
});

ipcMain.handle("app:isDarkMode", () => {
    return isDarkMode();
});

const getCurrentScreenDisplay = () => {
    const screenPoint = screen.getCursorScreenPoint();
    const display = screen.getDisplayNearestPoint(screenPoint);
    return {
        bounds: display.bounds,
        workArea: display.workArea,
    };
};

const calcPositionInCurrentDisplay = (
    position: "center" | "left-top" | "right-top" | "left-bottom" | "right-bottom",
    width: number,
    height: number
) => {
    const { bounds, workArea } = getCurrentScreenDisplay();
    let x = 0;
    let y = 0;
    switch (position) {
        case "center":
            x = workArea.x + (workArea.width - width) / 2;
            y = workArea.y + (workArea.height - height) / 2;
            break;
        case "left-top":
            x = workArea.x;
            y = workArea.y;
            break;
        case "right-top":
            x = workArea.x + workArea.width - width;
            y = workArea.y;
            break;
        case "left-bottom":
            x = workArea.x;
            y = workArea.y + workArea.height - height;
            break;
        case "right-bottom":
            x = workArea.x + workArea.width - width;
            y = workArea.y + workArea.height - height;
            break;
    }
    return {
        x: Math.round(x),
        y: Math.round(y),
    };
};

const toast = (
    msg: string,
    options?: {
        duration?: number;
        status?: "success" | "error" | "info";
    }
) => {
    return makeToast(msg, options);
};

ipcMain.handle("app:toast", (event, msg: string, option?: any) => {
    return toast(msg, option);
});

const loading = (
    msg: string,
    options?: {
        timeout?: number;
        percentAuto?: boolean;
        percentTotalSeconds?: number;
    }
): {
    close: () => void;
    percent: (value: number) => void;
} => {
    return makeLoading(msg, options);
};

ipcMain.handle("app:loading", (event, msg: string, option?: any) => {
    return loading(msg, option);
});

ipcMain.handle("app:setupList", async () => {
    return SetupMain.list();
});

ipcMain.handle("app:setupOpen", async (event, name: string) => {
    return SetupMain.open(name);
});

const setupIsOk = async () => {
    return SetupMain.isOk();
};

ipcMain.handle("app:setupIsOk", async () => {
    return setupIsOk();
});

const getBuildInfo = async () => {
    if (isDev) {
        return {
            buildId: "Development",
        };
    }
    const json = await Files.read(rendererDistPath("build.json"), {
        isDataPath: false,
    });
    return JSON.parse(json);
};

ipcMain.handle("app:getBuildInfo", async () => {
    return getBuildInfo();
});

const collect = async (options?: {}) => {
    return {
        userAgent: Apps.getUserAgent(),
        name: AppConfig.name,
        version: AppConfig.version,
        uuid: platformUUID(),
        platformVersion: platformVersion(),
        platformName: platformName(),
        platformArch: platformArch(),
    };
};

ipcMain.handle("app:collect", async (event, options?: {}) => {
    return collect(options);
});

const setAutoLaunch = async (enable: boolean, options?: {}) => {
    return app.setLoginItemSettings({
        openAtLogin: enable,
    });
};

ipcMain.handle("app:setAutoLaunch", async (event, enable: boolean, options?: {}) => {
    return setAutoLaunch(enable, options);
});

const getAutoLaunch = async (options?: {}) => {
    return app.getLoginItemSettings().openAtLogin;
};

ipcMain.handle("app:getAutoLaunch", async (event, options?: {}) => {
    return getAutoLaunch(options);
});

ipcMain.handle("app:getResourcesPath", () => {
    return getResourceRoot();
});

// FFprobe video info handler
ipcMain.handle("app:ffprobeVideoInfo", async (event, videoPath: string) => {
    const { getFFprobePath } = await import('../shell');

    try {
        const ffprobePath = await getFFprobePath();

        // 获取视频流信息和格式信息（包含时长）
        const args = [
            "-v", "error",
            "-show_entries", "stream=width,height,r_frame_rate:format=duration",
            "-of", "json",
            videoPath
        ];

        return new Promise((resolve, reject) => {
            const child = spawn(ffprobePath, args, { shell: false });
            let stdout = '';
            let stderr = '';

            child.stdout.on('data', (data) => {
                stdout += data.toString();
            });

            child.stderr.on('data', (data) => {
                stderr += data.toString();
            });

            child.on('close', (code) => {
                if (code !== 0) {
                    reject(new Error(`ffprobe failed with code ${code}: ${stderr}`));
                    return;
                }

                try {
                    const data = JSON.parse(stdout);

                    // 获取时长
                    let duration = undefined;
                    if (data.format && data.format.duration) {
                        duration = parseFloat(data.format.duration);
                    }

                    // 如果有视频流，获取视频信息
                    if (data.streams && data.streams.length > 0) {
                        const stream = data.streams[0];
                        const width = parseInt(stream.width, 10) || undefined;
                        const height = parseInt(stream.height, 10) || undefined;

                        // 解析帧率
                        let fps = 30;
                        if (stream.r_frame_rate) {
                            const fpsParts = stream.r_frame_rate.split("/");
                            fps = fpsParts.length === 2
                                ? parseFloat(fpsParts[0]) / parseFloat(fpsParts[1])
                                : parseFloat(stream.r_frame_rate);
                        }

                        resolve({ width, height, fps, duration });
                    } else {
                        // 只有音频流的情况，只返回时长
                        resolve({ duration });
                    }
                } catch (e) {
                    reject(e);
                }
            });
        });
    } catch (error) {
        throw error;
    }
});

export default {
    quit,
};

export const AppsMain = {
    shouldDarkMode,
    defaultDarkModeBackgroundColor,
    getWindowByName,
    getClipboardText,
    setClipboardText,
    getClipboardImage,
    setClipboardImage,
    getCurrentScreenDisplay,
    calcPositionInCurrentDisplay,
    toast,
    loading,
    setupIsOk,
    windowOpen,
};
