<template>
  <div class="title">
    <h3>
      <component :is="renderIcon('antd CodeOutlined')" />
      脚本编辑
    </h3>
    <el-row>
      <el-divider direction="vertical" />
      <el-button :icon="renderIcon('Save')" link
                 @click="saveScripts">保存
      </el-button>
      <el-button :icon="renderIcon('antd PullRequestOutlined')" link
                 @click="syncScripts">拉取
      </el-button>
      <el-divider direction="vertical" />
      <el-button :icon="renderIcon('CirclePlus')" link
                 @click="addScript">添加
      </el-button>
      <el-button :icon="renderIcon('Delete')" link
                 :disabled="scriptList.length === 0 || !scriptList[scriptIndex]"
                 @click="removeCurrentScript">删除
      </el-button>
      <el-divider direction="vertical" />
      <el-button :icon="renderIcon('antd PlayCircleOutlined')" link type="primary"
                 v-if="scriptList[scriptIndex] && !scriptList[scriptIndex].isRunning"
                 @click="()=>runScript(scriptList[scriptIndex])">运行脚本
      </el-button>
      <el-button :icon="renderIcon('antd StopOutlined')" link type="danger"
                 v-if="scriptList[scriptIndex] && scriptList[scriptIndex].isRunning"
                 @click="()=>stopScript(scriptList[scriptIndex])">停止运行
      </el-button>
      <el-button :icon="renderIcon('fa EyeDropper')" link
                 :disabled="scriptList.length === 0 || !scriptList[scriptIndex]"
                 @click="setCodeDropper">编码吸管
      </el-button>
      <el-divider direction="vertical" />
      <el-radio-group v-model="scriptIndex" size="small">
        <!-- 用 vue3-menus 在这里加一个右键，重命名-->
        <el-radio-button v-for="(item, index) in scriptList" :key="index" :class="'script_'+index"
                         :label="item.name" :value="index" v-menus="scriptMenu" />
      </el-radio-group>
      <el-button link v-if="scriptList[scriptIndex]"
                 @click="()=>localRun(scriptList[scriptIndex])">LocalRun
      </el-button>
    </el-row>
    <span class="close" @click="closeMe">
      <component :is="renderIcon('element Close')"></component>
    </span>
  </div>
  <div class="calc-bottom-panel">
    <YvSrcEditor ref="jsEditor" language="typescript" :key="scriptIndex"
                 v-if="scriptList.length > 0 && scriptList[scriptIndex]"
                 v-model="currentScript" />
  </div>
</template>
<script>
import localforage from 'localforage'
import YvSrcEditor from '@/components/YvSrcEditor.vue'
import IWidgets from '../IWidgets.js'
import CodeDropper from '@/core/manager/CodeDropper.js'
import { escByKeyboard } from '@/core/ModelUtils.js'
import scriptRunner from '@/runtime/ScriptRunner.js'

export default {
  name: 'ScriptView',
  components: {
    YvSrcEditor
  },
  mixins: [IWidgets],
  mounted() {
    window['ScriptView'] = this
  },
  unmounted() {
    window['ScriptView'] = null
  },
  data() {
    const me = this

    return {
      scriptIsRunning: false,
      scriptIndex: 0,
      /**
       * 脚本列表
       * @type {Array<CustomScript>}
       */
      scriptList: [],
      searchKeyword: '',
      scriptMenu: [
        {
          name: 'removeScript', label: '删除',
          click(menu, { class: classJoinStr }) {
            // 拿到 classJoinStr 最后一截字符串, 取到 scriptIndex
            const index = parseInt(classJoinStr.split('_').pop())
            if (isNaN(index) || index < 0 || index >= me.scriptList.length) {
              system.msg('脚本索引错误', 'error')
              return
            }
            const script = me.scriptList[index]
            if (!script) {
              system.msg('脚本不存在', 'error')
              return
            }
            if (confirm(`确定要删除脚本 "${script.name}" 吗？`)) {
              _.remove(me.scriptList, (item, idx) => idx === index)
              if (me.scriptList.length === 0) {
                me.scriptIndex = 0
              } else if (me.scriptIndex >= me.scriptList.length) {
                me.scriptIndex = me.scriptList.length - 1
              }
            }
          }
        },
        {
          name: 'rename', label: '重命名',
          click(menu, { class: classJoinStr }) {
            // 拿到 classJoinStr 最后一截字符串, 取到 scriptIndex
            const index = parseInt(classJoinStr.split('_').pop())
            if (isNaN(index) || index < 0 || index >= me.scriptList.length) {
              system.msg('脚本索引错误', 'error')
              return
            }
            const script = me.scriptList[index]
            if (!script) {
              system.msg('脚本不存在', 'error')
              return
            }
            const newName = prompt('请输入新的脚本名称', script.name)
            if (newName && newName.trim()) {
              script.name = newName.trim()
            }
          }
        }
      ]
    }
  },
  watch: {
    scriptList: {
      handler(newVal) {
        this.saveScriptsToLocalDebounce(this)
      },
      deep: true
    }
  },
  created() {
    this.loadFromLocal()
  },
  methods: {
    async saveScripts() {
      system.showLoading()
      try {
        await LCC.saveScripts(this.scriptList)
        system.msg('脚本已保存')

      } finally {
        system.clearLoading()
      }
    },
    async syncScripts() {
      // 保存当前脚本索引
      const originName = this.scriptList[this.scriptIndex]?.name
      system.showLoading()
      try {
        const serverResponse = await LCC.syncScripts()
        if (serverResponse.success) {
          this.scriptList = serverResponse.data || []

          // 从 originName 中找到对应的脚本索引
          if (originName) {
            const index = this.scriptList.findIndex(item => item.name === originName)
            if (index >= 0) {
              this.scriptIndex = index
              return
            }
          }

          this.scriptIndex = 0
        }

        system.msg('脚本已同步')

      } finally {
        system.clearLoading()
      }
    },
    /**
     * 运行脚本
     * @type {(script: CustomScript) => void}
     */
    runScript(script) {
      system.showLoading()
      scriptRunner.runScript(script)
        .finally(() => {
          system.clearLoading()
        })
      // this.viewport.modelManager.runScript(script)
    },

    /**
     * 停止脚本
     * @type {(script: CustomScript) => void}
     */
    stopScript(script) {
      scriptRunner.stopScript(script)
    },
    localRun(script) {
      this.viewport.modelManager.executestring(script.content)
    },
    setCodeDropper() {
      CodeDropper.start(this.viewport, (item) => {
        if (item) {
          if (!this.$refs.jsEditor) {
            system.msg('代码编辑器未加载', 'warning')
            return false
          }
          //@ts-ignore
          this.$refs.jsEditor.insertText(`Model.find("${item.id}")`)
          //@ts-ignore
          this.$refs.jsEditor.focus()
          return true

        } else {
          system.msg('代码吸管没有获取到内容', 'warning')
          return false
        }
      })
    },
    saveScriptsToLocal() {
      localforage.setItem('-yvan-lcc-scriptlist-', JSON.stringify({
        scriptList: _.map(this.scriptList, item => {
          return {
            name: item.name,
            content: item.content
          }
        }),
        scriptIndex: this.scriptIndex

      })).catch(err => {
        system.msg('保存脚本到本地失败:', 'error')
      })
    },
    saveScriptsToLocalDebounce: _.debounce(function(me) {
      me.saveScriptsToLocal()
    }, 1000),
    loadFromLocal() {
      localforage.getItem('-yvan-lcc-scriptlist-')
        .then(value => {
          if (value) {
            const res = JSON.parse(value)
            this.scriptList = res.scriptList || []
            this.scriptIndex = res.scriptIndex || 0
          } else {
            this.scriptList = []
          }
        })
        .catch(err => {
          this.scriptList = []
          system.msg('加载脚本失败:', 'error')
        })
    },
    addScript() {
      this.scriptList.push({
        name: 'Script' + (this.scriptList.length + 1),
        content: '',
        isRunning: false
      })
      this.scriptIndex = this.scriptList.length - 1
    },
    removeCurrentScript() {
      _.remove(this.scriptList, (item, index) => {
        return index === this.scriptIndex
      })
      if (this.scriptList.length === 0) {
        this.scriptIndex = 0
      } else if (this.scriptIndex >= this.scriptList.length) {
        this.scriptIndex = this.scriptList.length - 1
      }
    }
  },
  computed: {
    currentScript: {
      get() {
        return this.scriptList[this.scriptIndex]?.content || ''
      },
      set(value) {
        if (!this.scriptList[this.scriptIndex]) {
          this.scriptList[this.scriptIndex] = {
            name: 'Script' + (this.scriptList.length + 1),
            content: '',
            isRunning: false
          }
        }
        this.scriptList[this.scriptIndex].content = value
      }
    }
  }
}
</script>
<style lang="less">
.title {
  & > h3 {
    margin-right: 10px;

    .el-icon {
      position: relative;
      top: 2px;
    }
  }

  & > .el-row {
    display: flex;
    align-items: center;
  }
}
</style>
