/**
 * 主窗口
 */

import { ipcMain, BrowserWindow, type BrowserWindowConstructorOptions } from "electron"
import * as remote from "@electron/remote/main"
import GlobalConfig from "./GlobalConfig"
import { mainLog } from "../utils/logger"
import { spawn } from "child_process"

class WinMain {
  /** 窗口实例 */
  private static WIN_INST: BrowserWindow | null = null

  /** 窗口配置 */
  private static WIN_CONFIG: BrowserWindowConstructorOptions = {
    icon: GlobalConfig.getAppLogo(), // 图标
    title: GlobalConfig.getAppTitle(), // 如果由 loadURL() 加载的 HTML 文件中含有标签 <title>，此属性将被忽略
    minWidth: 500,
    minHeight: 400,
    show: false, // 是否在创建时显示, 默认值为 true
    frame: true, // 设置为false来隐藏标题栏
    center: true, // 是否在屏幕居中
    hasShadow: false, // 窗口是否有阴影. 默认值为 true
    resizable: true, // 是否允许拉伸大小
    fullscreenable: true, // 是否允许全屏，为 false 则插件 screenfull 不起作用
    autoHideMenuBar: true, // 自动隐藏菜单栏, 除非按了 Alt 键, 默认值为 false
    backgroundColor: "#fff", // 背景颜色
    webPreferences: {
      spellcheck: false, // 禁用拼写检查器
      disableBlinkFeatures: "SourceMap", // 以 "," 分隔的禁用特性列表
      devTools: true, // 是否开启 DevTools, 如果设置为 false（默认值为 true）, 则无法使用 BrowserWindow.webContents.openDevTools()
      webSecurity: false, // 当设置为 false, 将禁用同源策略
      nodeIntegration: true, // 是否启用 Node 集成
      contextIsolation: false, // 是否在独立 JavaScript 环境中运行 Electron API 和指定的 preload 脚本，默认为 true
      backgroundThrottling: false, // 是否在页面成为背景时限制动画和计时器，默认值为 true
      nodeIntegrationInWorker: true // 是否在 Web 工作器中启用了 Node 集成
    }
  }

  /** 获取窗口实例 */
  static getWinInst() {
    return this.WIN_INST
  }

  /** 显示窗口 */
  static show(key?: string, center?: boolean) {
    mainLog.log("[show main win] ", key)
    this.WIN_INST?.show()
    this.WIN_INST?.focus()
    center && this.WIN_INST?.center()
  }

  /** 创建窗口 */
  static create() {
    if (this.WIN_INST) return

    this.WIN_INST = new BrowserWindow(this.WIN_CONFIG)
    this.WIN_INST.removeMenu()

    if (GlobalConfig.IS_DEV_MODE) {
      this.WIN_INST.loadURL(GlobalConfig.getWinUrl())
    } else {
      this.WIN_INST.loadFile(GlobalConfig.getWinUrl())
    }

    // 启用 remote
    remote.enable(this.WIN_INST.webContents)

    // 窗口-准备好显示
    // 在窗口的控制台中使用 F5 刷新时，也会触发该事件
    this.WIN_INST.on("ready-to-show", () => {
      this.show("win=>ready-to-show", true)
      GlobalConfig.IS_DEV_MODE && this.openDevTools()
    })

    // 窗口-即将关闭
    this.WIN_INST.on("close", () => {})

    // 窗口-已关闭
    this.WIN_INST.on("closed", () => (this.WIN_INST = null))
  }

  /** 打开控制台 */
  static openDevTools() {
    if (!this.WIN_INST) return
    const winCtns = this.WIN_INST.webContents
    if (winCtns.isDevToolsOpened()) return
    winCtns.openDevTools({ mode: "undocked", title: "tools" })
  }

  /** 监听通信事件 */
  static ipcListening() {
    // 中转消息-代替中央事件总线
    ipcMain.on("vue_bus", (_, { channel, data }) => {
      if (!this.WIN_INST || !channel) return
      this.WIN_INST.webContents.send(channel, data)
    })
    // 设置窗口最小值
    ipcMain.on("set_min_size", (_, dto: WinStateDTO) => {
      if (!this.WIN_INST) return
      const size = GlobalConfig.adaptByScreen(dto, this.WIN_INST)
      const val = this.WIN_INST.isResizable()
      this.WIN_INST.setResizable(true)
      this.WIN_INST.setMinimumSize(size.width, size.height)
      this.WIN_INST.setSize(size.width, size.height)
      this.WIN_INST.setResizable(val)
    })
    // 设置窗口大小
    ipcMain.on("set_win_size", (_, dto: WinStateDTO) => {
      if (!this.WIN_INST) return
      const size = GlobalConfig.adaptByScreen(dto, this.WIN_INST)
      this.WIN_INST.setResizable(true)
      this.WIN_INST.setSize(size.width, size.height)
      dto.center && this.WIN_INST.center()
      this.WIN_INST.setMaximizable(dto.maxable)
      this.WIN_INST.setResizable(dto.resizable)
    })
    // 获取项目地址
    ipcMain.handle("project-address", () => {
      return process.cwd()
    })
    ipcMain.handle("cmd-comm", (_, dir: string, comm: string) => {
      return new Promise((resolve, reject) => {
        const cmd = spawn("cmd", [dir, comm])

        cmd.stdout.on("data", (data) => {
          resolve(`stdout: ${data}`)
        })

        cmd.stderr.on("data", (data) => {
          reject(`stderr: ${data}`)
        })

        cmd.on("close", (code) => {
          console.log(`child process exited with code ${code}`)
        })
      })
    })
  }
}

export default WinMain
