import type { AppMeta } from '@/types/appMeta'
import type { Bin } from '@/types/bins'
import type { ImageResource, OtherResource, FontResource } from '@/types/resource'
import type { VariableGroup } from '@/types/variables'
import type { Theme } from '@/types/theme'
import type { Animation } from '@/types/animation'
import type { Language } from '@/types/language'
import type { Method } from '@/types/method'
import type { BaseWidget } from '@/types/baseWidget'
import type { Screen } from '@/types/screen'
import type { Page } from '@/types/page'

import { computed, ref, watch } from 'vue'
import { defineStore } from 'pinia'
import { klona } from 'klona'
import { createBin, createScreen } from '@/model'
import { useRecentProject } from './recentProject'
import { v4 } from 'uuid'
import dayjs from 'dayjs'
import { ElMessage } from 'element-plus'
import { useI18n } from 'vue-i18n'
import { ComponentArray } from '@/lvgl-widgets'
import { bfsWalk } from 'simple-mind-map/src/utils'
import { useHistory } from '@/hooks/useHistory'
import { DEFAULT_THEME_KEY } from '@/constants'

export interface IProject {
  version: string
  meta: AppMeta
  bins: Bin[]
  resources: {
    images: ImageResource[]
    fonts: FontResource[]
    others: OtherResource[]
  }
  widgets: BaseWidget[]
  variables: VariableGroup[]
  themes: Theme[]
  animations: Animation[]
  languages: Language[]
  methods: Method[]
  screens: Screen[]
  currentLanguage?: string
  currentTheme?: string
}

export const useProjectStore = defineStore('project', () => {
  const {
    initHistory,
    history,
    undo,
    redo,
    canRedo,
    canUndo,
    clear,
    project,
    openPageIds,
    activePageId,
    activeWidgets
  } = useHistory()

  // 项目文件夹
  const projectDirectory = ref<string>()
  // 全局样式
  const globalStyle = ref<any[]>()

  const recentProjectStore = useRecentProject()
  const { t } = useI18n()

  // 图片压缩格式
  const imageCompressFormat = ref<string[]>([])
  // 当前最大化屏幕
  const currentMaxScreen = ref<string | null>(null)

  // 当前激活的页面
  const activePage = computed(() => {
    const pages = project.value?.screens.map((screen) => screen.pages)
    return pages?.flat().find((page) => page.id === activePageId.value)
  })
  // 当前激活的屏幕
  const activeScreen = computed(() => {
    return project.value?.screens.find((screen) =>
      screen.pages.some((page) => page.id === activePageId.value)
    )
  })

  // 项目路径
  const projectPath = computed(() => {
    if (!project.value) return ''

    return `${project.value.meta.path}\\${projectDirectory.value}`
  })

  // 打开页面 用以记录每个屏幕打开的页面
  const openPages = computed(() => {
    const pages: Page[] = []
    openPageIds.value.forEach((id) => {
      project.value?.screens.forEach((screen) =>
        screen.pages.find((page) => {
          if (page.id === id) {
            pages.push(page)
          }
        })
      )
    })
    return pages
  })

  // 当前激活的元素
  const activeWidget = computed(() => {
    return activeWidgets.value?.at(-1) ?? activePage.value
  })

  watch(
    () => activePageId,
    () => {
      activeWidgets.value = []
    }
  )

  const checkNotLoadFont = (fontName: string) => {
    return new Promise((resolve, reject) => {
      document.fonts.ready.then(function () {
        document.fonts.forEach(function (fontFace) {
          if (fontFace.family === fontName) {
            reject()
          }
        })

        resolve(true)
      })
    })
  }

  watch(
    () => project.value?.resources.fonts,
    async (fonts?: FontResource[]) => {
      // 动态加载全部字体
      // 判断字体是否已经加载
      const fontPromises = fonts
        ?.filter(async (font) => await checkNotLoadFont(font.fileName))
        .map((font) => {
          const fontFace = new FontFace(
            font.fileName,
            `url('local:///${projectPath.value + font.path}')`.replaceAll('\\', '/')
          )
          return fontFace.load()
        })

      if (fontPromises?.length) {
        Promise.all(fontPromises)
          .then((loadedFonts) => {
            console.log('已加载字体:', loadedFonts)
            loadedFonts.forEach((font) => document.fonts.add(font))
            console.log('所有字体已加载并可用')
          })
          .catch((err) => console.error('字体加载失败:', err))
      }
    },
    {
      deep: true,
      immediate: true
    }
  )

  // 当前激活元素map
  const activeWidgetMap = computed(() => {
    return activeWidgets.value.reduce((acc, cur) => {
      acc[cur.id] = cur
      return acc
    }, {})
  })

  const setCurrentTheme = (themeKey?: string) => {
    if (!project.value) return

    const targetTheme = themeKey || DEFAULT_THEME_KEY
    const hasTheme = (project.value.themes || []).some((item) => item.key === targetTheme)
    project.value.currentTheme = hasTheme ? targetTheme : DEFAULT_THEME_KEY
  }

  const normalizeThemes = () => {
    if (!project.value) return

    const list = Array.isArray(project.value.themes) ? project.value.themes : []
    const themes: Theme[] = []
    const keySet = new Set<string>()

    list.forEach((item) => {
      if (!item?.key || keySet.has(item.key)) return

      themes.push({
        key: item.key,
        default: item.key === DEFAULT_THEME_KEY,
        description: item.description || ''
      })
      keySet.add(item.key)
    })

    if (!keySet.has(DEFAULT_THEME_KEY)) {
      themes.unshift({
        key: DEFAULT_THEME_KEY,
        default: true,
        description: '默认主题'
      })
    } else {
      themes.sort(
        (a, b) => Number(b.key === DEFAULT_THEME_KEY) - Number(a.key === DEFAULT_THEME_KEY)
      )
    }

    project.value.themes = themes.map((item) => ({
      ...item,
      default: item.key === DEFAULT_THEME_KEY
    }))
    setCurrentTheme(project.value.currentTheme || DEFAULT_THEME_KEY)
  }

  const removeThemeStyles = (themeKey: string) => {
    if (!project.value || !themeKey || themeKey === DEFAULT_THEME_KEY) return

    project.value.screens.forEach((screen) => {
      screen.pages.forEach((page) => {
        if (Array.isArray(page.style)) {
          page.style = page.style.filter((item: any) => item?.theme !== themeKey)
        }

        bfsWalk(page, (widget) => {
          if (Array.isArray(widget.style)) {
            widget.style = widget.style.filter((item: any) => item?.theme !== themeKey)
          }
        })
      })
    })
  }

  const renameThemeStyles = (fromThemeKey: string, toThemeKey: string) => {
    if (!project.value || !fromThemeKey || !toThemeKey || fromThemeKey === toThemeKey) return

    project.value.screens.forEach((screen) => {
      screen.pages.forEach((page) => {
        if (Array.isArray(page.style)) {
          page.style.forEach((item: any) => {
            if (item?.theme === fromThemeKey) {
              item.theme = toThemeKey
            }
          })
        }

        bfsWalk(page, (widget) => {
          if (Array.isArray(widget.style)) {
            widget.style.forEach((item: any) => {
              if (item?.theme === fromThemeKey) {
                item.theme = toThemeKey
              }
            })
          }
        })
      })
    })

    if (project.value.currentTheme === fromThemeKey) {
      project.value.currentTheme = toThemeKey
    }
  }

  /**
   * 创建应用
   * @param meta 应用元信息
   */
  const createApp = async (meta: AppMeta) => {
    meta = klona(meta)
    meta.createTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
    meta.modifyTime = dayjs().format('YYYY-MM-DD HH:mm:ss')
    // 1、应用元信息
    project.value = {
      version: '1.0.0',
      currentLanguage: 'zh-CN',
      currentTheme: DEFAULT_THEME_KEY,
      meta: klona(meta),
      resources: {
        images: [],
        fonts: [],
        others: []
      },
      bins: [],
      widgets: [],
      variables: [],
      themes: [
        {
          key: DEFAULT_THEME_KEY,
          default: true,
          description: '默认主题'
        }
      ],
      animations: [],
      languages: [],
      methods: [],
      screens: []
    }
    // 2、构建屏幕信息
    activePageId.value = ''
    currentMaxScreen.value = null
    openPageIds.value = []
    activeWidgets.value = []
    meta.screens.forEach((screen, index) => {
      const newScreen = createScreen(screen)
      newScreen.name += `_${index + 1}`
      project.value?.screens.push(newScreen)
      openPageIds.value.push(newScreen.pages[0].id)
    })
    activePageId.value = project.value.screens[0].pages[0].id
    // 3、创建BIN
    if (meta.resourcePackaging === 'c_bin' && meta.binNum > 0) {
      for (let i = 0; i < meta.binNum; i++) {
        project.value.bins.push(createBin(i))
      }
    }

    projectDirectory.value = meta.name

    // projectPath.value = `${meta.path}/${meta.name}`
    // 4、创建项目文件夹
    await window.electron.ipcRenderer.invoke('create-directory', `${meta.path}\\${meta.name}\\src`)
    // // assets
    // await window.electron.ipcRenderer.invoke(
    //   'create-directory',
    //   `${meta.path}\\${meta.name}\\src\\assets`
    // )
    // images
    // await window.electron.ipcRenderer.invoke(
    //   'create-directory',
    //   `${meta.path}\\${meta.name}\\src\\assets\\images`
    // )
    // // fonts
    // await window.electron.ipcRenderer.invoke(
    //   'create-directory',
    //   `${meta.path}\\${meta.name}\\src\\assets\\fonts`
    // )
    // // others
    // await window.electron.ipcRenderer.invoke(
    //   'create-directory',
    //   `${meta.path}\\${meta.name}\\src\\assets\\others`
    // )

    // 将resources下的template的src目录复制到项目目录下
    await window.electron.ipcRenderer.invoke('copy-template', `${meta.path}\\${meta.name}\\src`)
    // 工程json
    await window.electron.ipcRenderer.invoke(
      'write-file',
      `${meta.path}\\${meta.name}\\project.ui`,
      JSON.stringify(project.value, null, 2)
    )

    // 全局样式
    globalStyle.value = klona(
      ComponentArray.map((item) => item?.defaultStyle).filter((item) => item)
    )

    // 全局样式json
    await window.electron.ipcRenderer.invoke(
      'write-file',
      `${meta.path}\\${meta.name}\\style.ui`,
      JSON.stringify(globalStyle.value, null, 2)
    )

    imageCompressFormat.value = meta.imageCompress
    // 清除记录
    initHistory()
    recentProjectStore.addProject({
      id: v4(),
      projectName: meta.name,
      projectPath: `${meta.path}\\${meta.name}`,
      createTime: meta.createTime,
      modifyTime: meta.modifyTime
    })

    // 锁定项目文件夹，防止用户在资源管理器中删除正在使用的项目目录
    window.electron.ipcRenderer.invoke('lock-project-folder', `${meta.path}\\${meta.name}`)
  }

  /**
   * 加载项目
   * @param newProject 项目字符串
   */
  const loadProject = (newProject: IProject, path: string, style: any) => {
    project.value = newProject
    normalizeThemes()
    globalStyle.value = style
    currentMaxScreen.value = null
    const projectPath = project.value.meta.path + '\\' + project.value.meta.name
    // 修改项目路径
    if (projectPath !== path) {
      projectDirectory.value = path.split('\\').pop()
      project.value.meta.path = path.slice(0, path.lastIndexOf('\\'))
    } else {
      projectDirectory.value = project.value.meta.name
    }
    // 初始化处理
    // projectPath.value = path
    openPageIds.value = newProject.screens
      .map((screen) => screen.pages?.[0]?.id)
      .filter((item) => item)
    activePageId.value = newProject.screens[0].pages?.[0]?.id
    activeWidgets.value = []
    imageCompressFormat.value = newProject.meta.imageCompress
    recentProjectStore.addProject({
      id: v4(),
      projectName: newProject.meta.name,
      projectPath: path,
      createTime: newProject.meta.createTime!,
      modifyTime: newProject.meta.modifyTime!
    })

    initHistory()

    // 锁定项目文件夹，防止用户在资源管理器中删除正在使用的项目目录
    window.electron.ipcRenderer.invoke('lock-project-folder', path)
  }

  // 保存当前项目
  const saveProject = async () => {
    if (!projectPath.value) {
      ElMessage.error(t('projectNotExist'))
      return
    }
    // 1、保存项目
    await window.electron.ipcRenderer.invoke(
      'write-file',
      `${projectPath.value}\\project.ui`,
      JSON.stringify(project.value, null, 2)
    )
    // 2、更新修改时间
    recentProjectStore.updateProject({
      ...recentProjectStore.currentRecord!,
      modifyTime: dayjs().format('YYYY-MM-DD HH:mm:ss')
    })
    ElMessage.success(t('saveSuccess'))
  }

  // 打开本地项目
  const openLocalProject = async () => {
    const paths = await window.electron.ipcRenderer.invoke('get-file', {
      title: t('chooseProject'),
      buttonLabel: t('open'),
      properties: ['openFile'],
      filters: [
        {
          name: 'Project',
          extensions: ['ui']
        }
      ]
    })
    const path = paths?.[0]
    if (!path) return
    // 存在 打开项目
    let msg
    try {
      msg = ElMessage.info({
        message: t('openingProject'),
        duration: 0,
        plain: true
      })
      const result = await window.electron.ipcRenderer.invoke('read-file', path, 'utf-8')
      const globalStylePath = path.replace('project.ui', 'style.ui')
      const style = await window.electron.ipcRenderer.invoke('read-file', globalStylePath, 'utf-8')
      if (result) {
        loadProject(JSON.parse(result), path.slice(0, path.lastIndexOf('\\')), JSON.parse(style))
        ElMessage.success({
          message: t('openProjectSuccess'),
          plain: true
        })
      } else {
        // 读取失败 删除项目
        ElMessage.error(t('readProjectError'))
      }
    } finally {
      msg?.close()
    }
  }

  /**
   * 选中元素
   * @param widgets 选中的元素
   */
  const setSelectWidgets = (widgets: BaseWidget[]) => {
    activeWidgets.value = widgets
  }

  /**
   * 根据id获取widget
   * @param id
   * @returns widget
   */
  const getWidgetById = (id: string): BaseWidget | undefined => {
    if (!project.value) return
    let widget: BaseWidget | undefined
    project.value.screens.find((screen) => {
      return screen.pages.find((page) => {
        return bfsWalk(page, (child) => {
          if (child.id === id) {
            widget = child
          }
        })
      })
    })

    return widget
  }

  return {
    createApp,
    project,
    activePageId,
    activePage,
    activeWidget,
    projectPath,
    imageCompressFormat,
    loadProject,
    openLocalProject,
    saveProject,
    activeWidgets,
    openPageIds,
    openPages,
    setSelectWidgets,
    activeWidgetMap,
    globalStyle,
    currentMaxScreen,
    activeScreen,
    getWidgetById,
    setCurrentTheme,
    normalizeThemes,
    removeThemeStyles,
    renameThemeStyles,

    // 历史记录
    history,
    undo,
    redo,
    canRedo,
    canUndo,
    clear
  }
})
