<script setup lang="ts">

import {computed, reactive, Ref, ref, watch} from "vue";
import {TableIdentifier, Transforms, useAPI, VirtualViewCreation} from "@/services/api";
import {useMainStore} from "@/services/mainStore";
import {useSelectionStore} from "@/services/selectionStore";
import SimpleJoin from "@/components/subcomponents/transform/SimpleJoin.vue";
import ExtractJson from "@/components/subcomponents/transform/ExtractJson.vue";
import EditColumns from "@/components/subcomponents/transform/EditColumns.vue";
import TableFilter from "@/components/subcomponents/transform/TableFilter.vue";
import TimeFilter from "@/components/subcomponents/transform/TimeFilter.vue";
import TableSelector from "@/components/helpers/TableSelector.vue";
import {storeToRefs} from "pinia";
import InfoDialog from "@/components/helpers/InfoDialog.vue";
import {rules} from "@/services/utils";
import AdvancedRaw from "@/components/subcomponents/transform/AdvancedRaw.vue";

type WidgetKind = "base" | "transform" | "advanced"

const modes = [
  {title: "Join", value: "base"},
  {title: "Transform", value: "transform"},
  {title: "Advanced", value: "advanced"}]
const widgetComponents: { title: string, value: string, kind: WidgetKind }[] = [
  {
    title: "Advanced Raw",
    value: "advancedRaw",
    kind: "advanced"
  },
  {
    title: "Column Editor",
    value: "editColumns",
    kind: "transform"
  }, {
    title: "JSON Extractor",
    value: "extractJson",
    kind: "transform"
  }, {
    title: "Table Filter",
    value: "tableFilter",
    kind: "transform"
  },
  {
    title: "Simple Join",
    value: "simpleJoin",
    kind: "base"
  },
]


const widgetInstances: { [key: string]: { ref: any, isValid: Ref<boolean>, kind: WidgetKind, cls: any } } = {
  "editColumns": {cls: EditColumns, ref: ref(), isValid: ref<boolean>(false), kind: "transform"},
  "extractJson": {cls: ExtractJson, ref: ref(), isValid: ref<boolean>(false), kind: "transform"},
  "tableFilter": {cls: TableFilter, ref: ref(), isValid: ref<boolean>(false), kind: "transform"},
  "simpleJoin": {cls: SimpleJoin, ref: ref(), isValid: ref<boolean>(false), kind: "base"},
  "advancedRaw": {cls: AdvancedRaw, ref: ref(), isValid: ref<boolean>(false), kind: "advanced"},
}

const store = useMainStore()
const selection = useSelectionStore()
const api = useAPI()
const {virtualDBSchema} = storeToRefs(store)
const {selectedTable} = storeToRefs(selection)

const dialog = reactive({content: "", show: false, success: null, title: "Virtual View Creation"})
const loading = ref(false)
const mode = ref("transform")
const removeBaseTable = ref(false)
const permitOverride = ref(true)
const viewIdentifier = reactive<TableIdentifier>({source: "virtual", schema: "virtual", name: ""})

const tab = ref("columnEdit")

const widgetList = computed(() => {
  const kind = mode.value
  return widgetComponents.filter(item => item.kind === kind)
})

watch(widgetList, (wl) => tab.value = wl[0].value, {flush: "post"})

const widgetInstance = computed(() => widgetInstances[tab.value])

const widgetComponent = computed(() => widgetInstance.value.cls)

const isValid = computed(() => (mode.value !== "transform" || !!selectedTable.value) && !!viewIdentifier.schema && !!viewIdentifier.name && uniqueName())

const disabled = computed(() => {
  const selfValid = isValid.value
  const widgetValid = widgetInstance.value?.isValid.value
  return !selfValid || !widgetValid
})


function createRequest(base: Transforms.Base, transforms: Transforms.Transform[]): VirtualViewCreation {
  return {
    name: viewIdentifier.name,
    schema: viewIdentifier.schema,
    table_creation: base,
    transforms: transforms
  }
}

async function attemptCreation(request: VirtualViewCreation, options?: {
  dropBase: boolean,
  base: TableIdentifier
}): Promise<boolean> {
  loading.value = true

  const r = await api.createVirtualView(request, {override_if_exists: permitOverride.value})

  const success = !!r?.data
  dialog.success = success
  if (success) {
    dialog.content = `"${r.data.table_meta.name}" has been created`

    if (options?.dropBase) {
      const t = options.base
      const r2 = await api.dropVirtualView({schema: t.schema, view: t.name})
      if (r2)
        dialog.content += ` and its base ${t.name} has been dropped`

    }
  } else {
    dialog.content = `Virtual view creation has failed`
  }
  dialog.show = true

  loading.value = false

  return success
}

async function onSubmit() {
  const widget = widgetInstance.value
  if (!widget) return
  let base = {operation: "existing", base_table: selectedTable.value} as Transforms.ExistingTable
  let transforms = []
  if (widget.kind === "base" || widget.kind === "advanced")
    base = widget.ref.createBase()
  if (widget.kind === "transform" || widget.kind === "advanced")
    transforms = widget.ref.createTransforms()
  const r = createRequest(base, transforms)
  attemptCreation(r).then(s => !!s && setTimeout(store.reloadVirtualDB, 500))
}

function uniqueName(v) {
  return permitOverride.value || !Object.values(virtualDBSchema.value.tables).some(tm => tm.schema_name === viewIdentifier.schema && tm.name === viewIdentifier.name) || "view already exists"
}

function resetWidget() {
  const widget = widgetInstance.value;
  if (!!widget) widget.ref.resetAll()
}

</script>

<template>
  <v-card title="Create Virtual View" class="fill-height" variant="text">
    <v-container fluid>
      <v-row justify="start" align="start" class="d-flex">
        <v-col cols="2">
          <v-select label="Mode" :items="modes" v-model="mode" hide-details variant="solo"></v-select>
        </v-col>
        <v-col cols="3">
          <v-text-field label="Schema Name" :rules="[rules.required, uniqueName]"
                        prepend-icon="mdi-folder-pound-outline"
                        v-model="viewIdentifier.schema"
                        validate-on="invalid-input eager" clearable></v-text-field>
        </v-col>
        <v-col cols="4">
          <v-text-field label="View Name" :rules="[rules.required, uniqueName]" prepend-icon="mdi-table"
                        v-model="viewIdentifier.name"
                        validate-on="invalid-input eager" clearable></v-text-field>
        </v-col>
      </v-row>

      <template v-if="mode === 'transform'">
        <v-row justify="start" align="center" class="text-center">
          <v-col cols="4">
            <TableSelector v-model:selected-table="selectedTable" source-d-b="either"
                           :props="{'hide-details': true}"></TableSelector>
          </v-col>
          <v-col cols="4">
            <v-checkbox label="remove base table afterwards?" density="compact"
                        v-model="removeBaseTable" hide-details></v-checkbox>
          </v-col>
          <v-col cols="4">
            <v-checkbox label="permit overriding existing table" density="compact"
                        v-model="permitOverride" hide-details></v-checkbox>
          </v-col>
        </v-row>
      </template>

    </v-container>
    <v-card class="pa-2" variant="outlined" min-height="200">
      <v-card-text>
        <v-tabs v-model="tab" align-tabs="start">
          <v-tab v-for="widget in widgetList" :text="widget.title" :value="widget.value" :key="widget.value"></v-tab>
        </v-tabs>
        <v-tabs-window v-model="tab" class="fill-height">
          <v-tabs-window-item v-for="(item, key) in widgetInstances" :value="key" :key="key">
            <component class="mx-auto" :is="item.cls" v-model="item.isValid.value" :ref="el => item.ref = el"
                       :table="selectedTable"></component>
          </v-tabs-window-item>
        </v-tabs-window>
        <v-divider></v-divider>
      </v-card-text>

      <v-card-actions>
        <v-spacer></v-spacer>
        <v-btn @click="resetWidget" type="reset">Reset</v-btn>
        <v-btn :disabled="disabled" type="submit" @click="onSubmit">Submit</v-btn>
      </v-card-actions>
    </v-card>

    <InfoDialog v-model:dialog="dialog"></InfoDialog>

  </v-card>

</template>

<style scoped>

</style>