<script setup lang="ts">
import SplitPane from './SplitPane.vue'
import Output from './output/Output.vue'
import { type Store, useStore } from './store'
import { computed, provide, ref, toRef, nextTick } from 'vue'
import { type EditorComponentType, injectKeyStore } from './types'
import EditorContainer from './editor/EditorContainer.vue'
import { renderIcon } from '@/utils';
import { icon } from '@/plugins';
const { FishIcon,SendIcon } = icon.ionicons5;
import { useRoute } from 'vue-router';
import { saveComponentData } from '@/api/demo/remote'

const route = useRoute();

export interface Props {
  theme?: 'dark' | 'light'
  previewTheme?: boolean
  editor: EditorComponentType
  store?: Store
  autoResize?: boolean
  showCompileOutput?: boolean
  showImportMap?: boolean
  showTsConfig?: boolean
  clearConsole?: boolean
  layout?: 'horizontal' | 'vertical'
  layoutReverse?: boolean
  ssr?: boolean
  previewOptions?: {
    headHTML?: string
    bodyHTML?: string
    placeholderHTML?: string
    customCode?: {
      importCode?: string
      useCode?: string
    }
  }
}

const props = withDefaults(defineProps<Props>(), {
  theme: 'light',
  previewTheme: false,
  store: () => useStore(),
  autoResize: true,
  showCompileOutput: true,
  showImportMap: true,
  showTsConfig: true,
  clearConsole: true,
  layoutReverse: false,
  ssr: false,
  previewOptions: () => ({
    headHTML: '',
    bodyHTML: '',
    placeholderHTML: '',
    customCode: {
      importCode: '',
      useCode: '',
    },
  }),
  layout: 'horizontal',
})

if (!props.editor) {
  throw new Error('The "editor" prop is now required.')
}

const outputRef = ref<InstanceType<typeof Output>>()
// 初始化编译
props.store.init()

const editorSlotName = computed(() => (props.layoutReverse ? 'right' : 'left'))
const outputSlotName = computed(() => (props.layoutReverse ? 'left' : 'right'))
const title = ref(route.params.id[0])
const focus = ref(false)
const inputInstRef = ref(null);
const data = ref()

provide(injectKeyStore, props.store)
provide('autoresize', props.autoResize)
provide('import-map', toRef(props, 'showImportMap'))
provide('tsconfig', toRef(props, 'showTsConfig'))
provide('clear-console', toRef(props, 'clearConsole'))
provide('preview-options', props.previewOptions)
provide('theme', toRef(props, 'theme'))
provide('preview-theme', toRef(props, 'previewTheme'))
/**
 * Reload the preview iframe
 */
function reload() {
  outputRef.value?.reload()
}

const handleFocus = () => {
  focus.value = true;
  nextTick(() => {
    inputInstRef.value && (inputInstRef.value as any).focus();
  });
};
const handleBlur = () => {
  focus.value = false;
}
const submit = () => {
  let params = {
    id: route.params.id[0],
    componentName: title.value,
    componentData: props.store.serialize()
  }
  saveComponentData(params).then(res => {
    if(res){
      window.$message.success('组件保存成功')
    }
  })
}

defineExpose({ reload })
</script>

<template>
  <div class="vue-repl">
    <div class="header">
      <div class="component-name-div">
        <n-icon size="20" :depth="3">
          <fish-icon></fish-icon>
        </n-icon>
        <n-text @click="handleFocus" style="white-space: nowrap;">
          组件名称  -   
            <n-button v-show="!focus" secondary size="tiny">
              <span class="title">
                {{ title }}
              </span>
          </n-button>
        </n-text>

        <n-input
          v-show="focus"
          ref="inputInstRef"
          size="small"
          type="text"
          maxlength="16"
          show-count
          placeholder="请输入项目名称"
          v-model:value.trim="title"
          @keyup.enter="handleBlur"
          @blur="handleBlur"
        ></n-input>
      </div>
      <div class="button-div">
        <n-button
          type="default"
          ghost
          @click="submit"
        >
          <template #icon>
            <component :is="renderIcon(SendIcon)"></component>
          </template>
          <span>{{ '保存组件' }}</span>
        </n-button>
      </div>
    </div>
    <SplitPane :layout="layout" :data="data">
      <template #[editorSlotName]>
        <!-- 编辑器 -->
        <EditorContainer :editor-component="editor" />
      </template>
      <template #[outputSlotName]>
        <Output
          ref="outputRef"
          :editor-component="editor"
          :show-compile-output="props.showCompileOutput"
          :ssr="!!props.ssr"
        />
      </template>
    </SplitPane>
  </div>
</template>

<style>

.vue-repl {
  --bg: #fff;
  --bg-soft: #f8f8f8;
  --border: #ddd;
  --text-light: #888;
  --font-code: Menlo, Monaco, Consolas, 'Courier New', monospace;
  --color-branding: #42b883;
  --color-branding-dark: #416f9c;
  --header-height: 38px;

  height: 100%;
  margin: 0;
  overflow: hidden;
  font-size: 13px;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
    Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
  background-color: var(--bg-soft);
}

.dark .vue-repl {
  --bg: #1a1a1a;
  --bg-soft: #242424;
  --border: #383838;
  --text-light: #aaa;
  --color-branding: #42d392;
  --color-branding-dark: #89ddff;
}

.vue-repl button {
  border: none;
  outline: none;
  cursor: pointer;
  margin: 0;
  background-color: transparent;
}
.header{
  width: 100%;
  height: 60px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-light);
}
.header .component-name-div{
  width: 300px;
  display: flex;
  align-items: center;
}
.header .button-div{
  position: absolute;
  right: 50px;
}
</style>
