<script setup lang="ts">
import { useToast } from 'vue-toastification'
import { Form } from 'ant-design-vue'
import type { TableType } from 'nocodb-sdk'
import type { UploadChangeParam } from 'ant-design-vue'
import { useI18n } from 'vue-i18n'
import MdiFileIcon from '~icons/mdi/file-plus-outline'
import MdiFileUploadOutlineIcon from '~icons/mdi/file-upload-outline'
import MdiLinkVariantIcon from '~icons/mdi/link-variant'
import MdiCodeJSONIcon from '~icons/mdi/code-json'
import { fieldRequiredValidator, importCsvUrlValidator, importExcelUrlValidator, importUrlValidator } from '~/utils/validation'
import { extractSdkResponseErrorMsg } from '~/utils/errorUtils'
import { ExcelTemplateAdapter, ExcelUrlTemplateAdapter, JSONTemplateAdapter, JSONUrlTemplateAdapter } from '~/utils/parsers'
import { useProject } from '#imports'
const { modelValue, importType } = defineProps<Props>()

const emit = defineEmits(['update:modelValue'])

const { t } = useI18n()

interface Props {
  modelValue: boolean
  importType: 'csv' | 'json' | 'excel'
}

const { tables } = useProject()
const toast = useToast()
const activeKey = ref('uploadTab')
const jsonEditorRef = ref()
const templateEditorRef = ref()
const loading = ref(false)
const templateData = ref()
const importData = ref()
const templateEditorModal = ref(false)
const useForm = Form.useForm

const importState = reactive({
  fileList: [],
  url: '',
  jsonEditor: {},
  parserConfig: {
    maxRowsToParse: 500,
    normalizeNested: true,
    importData: true,
  },
})

const validators = computed(() => {
  return {
    url: [fieldRequiredValidator, importUrlValidator, importType === 'csv' ? importCsvUrlValidator : importExcelUrlValidator],
    maxRowsToParse: [fieldRequiredValidator],
  }
})

const importMeta = computed(() => {
  if (importType === 'excel') {
    return {
      header: 'QUICK IMPORT - EXCEL',
      uploadHint: t('msg.info.excelSupport'),
      urlInputLabel: t('msg.info.excelURL'),
      loadUrlDirective: ['c:quick-import:excel:load-url'],
      acceptTypes: '.xls, .xlsx, .xlsm, .ods, .ots',
    }
  } else if (importType === 'csv') {
    return {
      header: 'QUICK IMPORT - CSV',
      uploadHint: '',
      urlInputLabel: t('msg.info.csvURL'),
      loadUrlDirective: ['c:quick-import:csv:load-url'],
      acceptTypes: '.csv',
    }
  } else if (importType === 'json') {
    return {
      header: 'QUICK IMPORT - JSON',
      uploadHint: '',
      acceptTypes: '.json',
    }
  }
  return {}
})

const dialogShow = computed({
  get() {
    return modelValue
  },
  set(v) {
    emit('update:modelValue', v)
  },
})

const { resetFields, validate, validateInfos } = useForm(importState, validators)

async function handlePreImport() {
  loading.value = true
  if (activeKey.value === 'uploadTab') {
    // FIXME:
    importState.fileList.map(async (file: any) => {
      await parseAndExtractData(file.data, file.name)
    })
  } else if (activeKey.value === 'urlTab') {
    try {
      await validate()
      await parseAndExtractData(importState.url, '')
    } catch (e: any) {
      toast.error(await extractSdkResponseErrorMsg(e))
    }
  } else if (activeKey.value === 'jsonEditorTab') {
    await parseAndExtractData(JSON.stringify(importState.jsonEditor), '')
  }
  loading.value = false
}

async function handleImport() {
  loading.value = true
  await templateEditorRef.value.importTemplate()
  loading.value = false
  dialogShow.value = false
}

async function parseAndExtractData(val: any, name: string) {
  try {
    templateData.value = null
    importData.value = null
    const templateGenerator: any = getAdapter(name, val)
    if (!templateGenerator) {
      toast.error('Template Generator cannot be found!')
      return
    }
    await templateGenerator.init()
    templateGenerator.parse()
    templateData.value = templateGenerator.getTemplate()
    templateData.value.tables[0].table_name = populateUniqueTableName()
    importData.value = templateGenerator.getData()
    templateEditorModal.value = true
  } catch (e: any) {
    console.log(e)
    toast.error(await extractSdkResponseErrorMsg(e))
  }
}

function handleDrop(e: DragEvent) {
  console.log(e)
}

function rejectDrop(fileList: any[]) {
  fileList.map((file) => {
    return toast.error(`Failed to upload file ${file.name}`)
  })
}

function handleChange(info: UploadChangeParam) {
  const status = info.file.status
  if (status !== 'uploading') {
    const reader: any = new FileReader()
    reader.onload = (e: any) => {
      const target: any = importState.fileList.find((f: any) => f?.uid === info.file.uid)
      if (target) {
        target.data = e.target.result
      }
    }
    reader.readAsArrayBuffer(info.file.originFileObj)
  }
  if (status === 'done') {
    toast.success(`Uploaded file ${info.file.name} successfully`)
  } else if (status === 'error') {
    toast.error(`Failed to upload file ${info.file.name}`)
  }
}

function formatJson() {
  loading.value = true
  jsonEditorRef.value.format()
  loading.value = false
}

function populateUniqueTableName() {
  let c = 1
  while (tables.value.some((t: TableType) => t.title === `Sheet${c}`)) {
    c++
  }
  return `Sheet${c}`
}

function getAdapter(name: string, val: any) {
  if (importType === 'excel' || importType === 'csv') {
    if (activeKey.value === 'uploadTab') {
      return new ExcelTemplateAdapter(name, val, importState.parserConfig)
    } else if (activeKey.value === 'urlTab') {
      return new ExcelUrlTemplateAdapter(val, importState.parserConfig)
    }
  } else if (importType === 'json') {
    if (activeKey.value === 'uploadTab') {
      return new JSONTemplateAdapter(name, val, importState.parserConfig)
    } else if (activeKey.value === 'urlTab') {
      return new JSONUrlTemplateAdapter(val, importState.parserConfig)
    } else if (activeKey.value === 'jsonEditorTab') {
      return new JSONTemplateAdapter(name, val, importState.parserConfig)
    }
  }
  return {}
}
</script>

<template>
  <a-modal v-model:visible="dialogShow" width="max(90vw, 600px)" @keydown.esc="dialogShow = false">
    <a-typography-title class="ml-4 mb-4 select-none" type="secondary" :level="5">{{ importMeta.header }}</a-typography-title>
    <template #footer>
      <a-button key="back" @click="dialogShow = false">{{ $t('general.cancel') }}</a-button>
      <a-button v-if="activeKey === 'jsonEditorTab'" key="format" :loading="loading" @click="formatJson">Format JSON</a-button>
      <a-button v-if="!templateEditorModal" key="pre-import" type="primary" :loading="loading" @click="handlePreImport">{{
        $t('activity.import')
      }}</a-button>
      <a-button v-else key="import" type="primary" :loading="loading" @click="handleImport">{{ $t('activity.import') }}</a-button>
    </template>
    <TemplateEditor
      v-if="templateEditorModal"
      ref="templateEditorRef"
      :project-template="templateData"
      :import-data="importData"
      :quick-import-type="importType"
    />
    <a-tabs v-else v-model:activeKey="activeKey" hide-add type="editable-card" :tab-position="top">
      <a-tab-pane key="uploadTab" :closable="false">
        <template #tab>
          <span class="flex items-center gap-2">
            <MdiFileUploadOutlineIcon />
            Upload
          </span>
        </template>
        <div class="pr-10 pb-10 pt-5">
          <a-form-item :label="t('msg.info.footMsg')" v-bind="validateInfos.maxRowsToParse">
            <a-input-number id="x" v-model:value="importState.parserConfig.maxRowsToParse" :min="1" :max="50000" size="large" />
          </a-form-item>
          <a-upload-dragger
            v-model:fileList="importState.fileList"
            name="file"
            :multiple="true"
            :accept="importMeta.acceptTypes"
            list-type="picture"
            @change="handleChange"
            @drop="handleDrop"
            @reject="rejectDrop"
          >
            <MdiFileIcon size="large" />
            <p class="ant-upload-text">Click or drag file to this area to upload</p>
            <p class="ant-upload-hint">
              {{ importMeta.uploadHint }}
            </p>
          </a-upload-dragger>
        </div>
      </a-tab-pane>
      <a-tab-pane v-if="importType === 'json'" key="jsonEditorTab" :closable="false">
        <template #tab>
          <span class="flex items-center gap-2">
            <MdiCodeJSONIcon />
            Json Editor
          </span>
        </template>
        <div class="pr-10 pb-10 pt-5">
          <MonacoEditor ref="jsonEditorRef" v-model="importState.jsonEditor" class="h-[400px]" />
        </div>
      </a-tab-pane>
      <a-tab-pane v-else key="urlTab" :closable="false">
        <template #tab>
          <span class="flex items-center gap-2">
            <MdiLinkVariantIcon />
            Url
          </span>
        </template>
        <div class="pr-10 pt-5">
          <a-form :model="importState" name="quick-import-url-form" layout="horizontal" class="mb-0">
            <a-form-item :label="importMeta.urlInputLabel" v-bind="validateInfos.url">
              <a-input v-model:value="importState.url" size="large" />
            </a-form-item>
          </a-form>
        </div>
      </a-tab-pane>
    </a-tabs>
  </a-modal>
</template>

<style scoped lang="scss">
:deep(.ant-upload-list) {
  overflow: auto;
  height: 300px;
}
</style>
