<script setup>
import { computed, ref, watch } from "vue";
import * as prettier from "prettier";
import prettierPluginHtml from "prettier/plugins/html";
import { useDocumentTemplate, validationRulesRegex, optionStringToChoiceObject } from "../../composables/document/template";
import {
  useDocumentTemplateInputTypes
} from "../../composables/document/templateInputTypes";
import { autoActionHeader, templateToHeader } from "../../composables/document/templateFormTable";
import { cloneDeep } from "lodash-es";
import VueJsonPretty from "vue-json-pretty";
import "vue-json-pretty/lib/styles.css";
import { safeParseJSONDeep } from "../../utils/object";
const props = defineProps({
  title: { type: String, required: false, default: "Document Template" },
  disableAdvanceMode: { type: Boolean, required: false, default: false }
});
const emit = defineEmits(["update:modelValue"]);
const modelValue = defineModel({ type: [String, Array] });
const advanceModeCode = ref();
const isAdvanceMode = computed(() => {
  return modelValue.value && (typeof modelValue.value === "string" && !isValidJsonArrayOfObjects(modelValue.value));
});
const templateItems = ref([]);
const headers = ref([
  {
    title: "",
    key: "operation",
    width: "120px"
  },
  {
    title: "Rec No.",
    key: "recNo"
  },
  {
    title: "Input Type",
    key: "inputType"
  },
  {
    title: "Width",
    key: "width"
  },
  {
    title: "Input Label",
    key: "inputLabel"
  },
  {
    title: "Variable Name",
    key: "variableName"
  },
  {
    title: "Configuration",
    key: "configuration"
  },
  {
    title: "Action",
    key: "action",
    width: "120px"
  }
]);
const formTableHeaders = ref([
  {
    title: "Title",
    key: "title"
  },
  {
    title: "Key",
    key: "key"
  },
  {
    title: "Width",
    key: "width"
  },
  {
    title: "Action",
    key: "action",
    width: "120px"
  }
]);
const choiceHeaders = ref([
  {
    title: "Label",
    key: "label"
  },
  {
    title: "Value",
    key: "value"
  },
  {
    title: "Action",
    key: "action",
    width: "120px"
  }
]);
function isValidJsonArrayOfObjects(str) {
  try {
    const parsed = JSON.parse(str);
    return Array.isArray(parsed) && parsed.every((item) => typeof item === "object" && item !== null && !Array.isArray(item));
  } catch (e) {
    return false;
  }
}
watch(templateItems, (newValue) => {
  if (!isAdvanceMode.value) modelValue.value = JSON.stringify(newValue);
}, { deep: true });
watch(modelValue, (newValue) => {
  if (typeof newValue === "string" && isValidJsonArrayOfObjects(newValue)) templateItems.value = JSON.parse(newValue);
  else if (typeof newValue === "string") advanceModeCode.value = newValue;
  else if (newValue) templateItems.value = cloneDeep(newValue);
}, { deep: true, immediate: true });
watch(advanceModeCode, (newValue) => {
  if (isAdvanceMode.value) modelValue.value = newValue;
});
async function convertToAdvanceMode() {
  if (!isAdvanceMode.value) {
    modelValue.value = await prettier.format(useDocumentTemplate(templateItems.value).replaceAll(">", ">\n"), { parser: "html", plugins: [prettierPluginHtml] });
  }
}
const inputTypes = computed(() => useDocumentTemplateInputTypes());
const inputTypeChoice = computed(() => inputTypes.value.map((t) => ({ label: t.label, value: t.value })));
const requireOption = computed(() => inputTypes.value.filter((t) => t.requiresOptions).map((t) => t.value));
const notRequireVariable = computed(() => inputTypes.value.filter((t) => t.needsVariableName === false).map((t) => t.value));
const notRequireLabel = computed(() => inputTypes.value.filter((t) => t.needsLabel === false).map((t) => t.value));
const notRequireWidth = computed(() => inputTypes.value.filter((t) => t.needsWidth === false).map((t) => t.value));
const notRequireOptions = computed(() => inputTypes.value.filter((t) => t.showsOptions === false).map((t) => t.value));
const notRequireRules = computed(() => inputTypes.value.filter((t) => t.hidesValidationRules).map((t) => t.value));
const notRequireInputAttributes = computed(() => inputTypes.value.filter((t) => t.hidesInputAttributes).map((t) => t.value));
const notRequireColumnAttributes = computed(() => inputTypes.value.filter((t) => t.hidesColumnAttributes).map((t) => t.value));
const notRequireAdvancedSetting = computed(() => inputTypes.value.filter((t) => t.hidesAdvancedSettings).map((t) => t.value));
const notRequireClassAndStyle = computed(() => inputTypes.value.filter((t) => t.hidesClassAndStyle).map((t) => t.value));
const hasSpecificOption = computed(() => inputTypes.value.filter((t) => t.hasSpecificOptionEditor).map((t) => t.value));
const choiceOption = computed(() => inputTypes.value.filter((t) => t.optionsAsChoice).map((t) => t.value));
const inputOptionsLabel = computed(() => {
  const acc = {};
  for (const t of inputTypes.value) if (t.optionsLabel) acc[t.value] = t.optionsLabel;
  return acc;
});
const ruleOptions = (inputType) => (value) => {
  if (choiceOption.value.includes(inputType) && !/^[^'",]+(,[^'",]+)*$/.test(value)) return "Invalid options format";
  return true;
};
</script>

<template>
  <FormTable
    v-if="!isAdvanceMode"
    v-model="templateItems"
    :headers="headers"
    :title="props.title"
  >
    <template #toolbarItems>
      <VBtn
        color="primary"
        variant="flat"
        @click="convertToAdvanceMode()"
        v-if="!disableAdvanceMode"
      >
        Convert To Advance
      </VBtn>
    </template>
    <template #item.recNo="{ internalItem }">
      {{ internalItem.index }}
    </template>
    <template #form="{ data, rules }">
      <v-container fluid>
        <v-row density="compact">
          <v-col cols="3">
            <v-combobox
              v-model="data.inputType"
              label="Input Type"
              :items="inputTypeChoice"
              item-title="label"
              item-value="value"
              :return-object="false"
              :rules="[rules.require()]"
            />
          </v-col>
          <v-col cols="1" v-if="!notRequireWidth.includes(data.inputType)">
            <v-text-field
              v-model="data.width"
              label="Width"
              :rules="[rules.require()]"
              type="number"
            />
            <form-hidden v-model="data.inputOptions" :item-value="data.inputType" :hook="(_result, model, newValue, oldValue) => {
  return newValue && oldValue ? void 0 : model;
}"></form-hidden>
          </v-col>
          <v-col cols="4" v-if="!notRequireLabel.includes(data.inputType)">
            <v-text-field
                v-model="data.inputLabel"
                label="Input Label"
                :rules="[rules.require()]"
            />
          </v-col>
          <v-col cols="4" v-if="!notRequireVariable.includes(data.inputType)">
            <v-text-field
                v-model="data.variableName"
                label="Variable Name"
                :rules="[rules.require()]"
            />
          </v-col>
          <v-col
              v-if="!notRequireOptions.includes(data.inputType)"
              cols="12"
          >
            <form-pad v-model="data.inputOptions" v-if="data.inputType == 'FormTable'">
              <template #default="{ data: optionData }">
                <v-row density="compact">
                  <v-col cols="12">
                    <form-table v-model="optionData.headers" :headers="formTableHeaders" title="Headers">
                      <template #form="{ data: headerData, rules }">
                        <v-container fluid>
                          <v-row density="compact">
                            <v-col cols="6"><v-text-field v-model="headerData.title" label="Title"></v-text-field></v-col>
                            <v-col cols="3"><v-text-field v-model="headerData.key" label="Key" :rules="[rules.require()]"></v-text-field></v-col>
                            <v-col cols="3"><v-text-field v-model="headerData.width" label="Width"></v-text-field></v-col>
                          </v-row>
                          <v-row density="compact">
                            <v-col cols="12"><v-textarea v-model="headerData.template" label="Item Template"></v-textarea></v-col>
                          </v-row>
                        </v-container>
                      </template>
                    </form-table>
                  </v-col>
                  <v-col cols="12">
                    <document-template-builder v-model="optionData.formTemplate" title="Form Template"></document-template-builder>
                  </v-col>
                </v-row>
              </template>
            </form-pad>
            <form-pad v-model="data.inputOptions" v-if="data.inputType == 'FormTableData'">
              <template #default="{ data: optionData }">
                <v-row density="compact">
                  <v-col cols="12">
                    <tabs-group>
                      <template #tabs>
                        <v-tab value="itemTemplate">Item Template</v-tab>
                        <v-tab value="dataTemplate">Data Template</v-tab>
                        <v-tab value="header">Header</v-tab>
                      </template>
                      <template #items>
                        <v-tabs-window-item value="itemTemplate">
                          <document-template-builder v-model="optionData.itemTemplate" title="Item Template" disable-advance-mode></document-template-builder>
                        </v-tabs-window-item>
                        <v-tabs-window-item value="dataTemplate">
                          <document-template-builder v-model="optionData.dataTemplate" title="Data Template" disable-advance-mode></document-template-builder>
                        </v-tabs-window-item>
                        <v-tabs-window-item value="header">
                          <form-table v-model="optionData.headers" :headers="formTableHeaders" title="Headers">
                            <template #form="{ data: headerData, rules }">
                              <v-container fluid>
                                <v-row density="compact">
                                  <v-col cols="6"><v-text-field v-model="headerData.title" label="Title"></v-text-field></v-col>
                                  <v-col cols="3"><v-text-field v-model="headerData.key" label="Key" :rules="[rules.require()]"></v-text-field></v-col>
                                  <v-col cols="3"><v-text-field v-model="headerData.width" label="Width"></v-text-field></v-col>
                                </v-row>
                                <v-row density="compact">
                                  <v-col cols="12"><v-text-field v-model="headerData.value" label="Value"></v-text-field></v-col>
                                  <v-col cols="12"><v-textarea v-model="headerData.template" label="Item Template"></v-textarea></v-col>
                                </v-row>
                              </v-container>
                            </template>
                          </form-table>
                        </v-tabs-window-item>
                      </template>
                    </tabs-group>
                  </v-col>
                  <v-col cols="12">
                    <form-table v-model="optionData.items" :headers="optionData.headers && optionData.headers.length > 0 ? autoActionHeader(optionData.headers) : autoActionHeader(templateToHeader(optionData.itemTemplate))" title="Items">
                      <template #form="{ data }">
                        <form-pad :model-value="data" :template="optionData.itemTemplate"></form-pad>
                      </template>
                    </form-table>
                  </v-col>
                  <v-col cols="12">
                    <v-row density="compact">
                      <v-col cols="4">
                        <v-radio-group v-model="optionData.disableApplyToAll" inline>
                          <template #prepend>
                            <span class="opacity-60"> Disable Apply to All</span>
                          </template>
                          <v-radio label="No" value="false" hide-details> </v-radio>
                          <v-radio label="Yes" value="true" hide-details> </v-radio>
                          <v-radio label="Partial" value="partial" hide-details> </v-radio>
                        </v-radio-group>
                      </v-col>
                      <v-col cols="8">
                        <VTextField
                            variant="underlined"
                            v-model="optionData.disableApplyToAllPartial"
                            label="Disable Apply To All Column"
                            v-if="optionData.disableApplyToAll == 'partial'"
                        >
                        </VTextField>
                      </v-col>
                    </v-row>
                  </v-col>
                </v-row>
              </template>
            </form-pad>
            <form-pad v-model="data.inputOptions" v-if="data.inputType == 'FormHidden'">
              <template #default="{ data: optionData }">
                <v-row density="compact">
                  <v-col cols="12">
                    <v-text-field
                        v-model="optionData.hook"
                        label="Hook"
                    />
                  </v-col>
                  <v-col cols="12">
                    <v-text-field
                        v-model="optionData.itemValue"
                        label="Item Value"
                    />
                  </v-col>
                </v-row>
              </template>
            </form-pad>
            <form-table v-model="data.inputOptions" :headers="choiceHeaders" title="Choices" v-if="choiceOption.includes(data.inputType) && (!data.inputOptions || typeof data.inputOptions === 'object')">
              <template #form="{ data: optionData, rules }">
                <v-container fluid>
                  <v-row density="compact">
                    <v-col cols="6"><v-text-field v-model="optionData.label" label="Label"></v-text-field></v-col>
                    <v-col cols="6"><v-text-field v-model="optionData.value" label="Value" :rules="[rules.require()]"></v-text-field></v-col>
                  </v-row>
                </v-container>
              </template>
            </form-table>
            <form-hidden v-model="data.inputOptions" :itemValue="data.inputOptions" :hook="(option) => optionStringToChoiceObject(option)" v-if="choiceOption.includes(data.inputType) && data.inputOptions && typeof data.inputOptions === 'string'"></form-hidden>
            <v-textarea
              v-model="data.inputOptions"
              :label="inputOptionsLabel[data.inputType] || 'Input Options'"
              auto-grow
              :rules="[rules.requireIf(requireOption.includes(data.inputType)), ruleOptions(data.inputType)]"
              v-if="!hasSpecificOption.includes(data.inputType) && !choiceOption.includes(data.inputType)"
            />
          </v-col>

          <v-col
            v-if="data.inputType == 'CustomCode'"
            cols="12"
          >
            <FormCodeEditor
                v-model="data.inputCustomCode"
                label="Custom Code"
                :rules="[rules.require()]"
            />
          </v-col>
        </v-row>
        <v-row density="compact">
          <v-col>
            <v-expansion-panels>
              <v-expansion-panel v-if="!notRequireRules.includes(data.inputType)">
                <v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Validations</v-expansion-panel-title>
                <v-expansion-panel-text>
                  <v-container fluid>
                    <v-row density="compact">
                      <v-col cols="12">
                        <v-text-field
                            v-model="data.validationRules"
                            label="Validation Rules"
                            :rules="[rules.regex(validationRulesRegex)]"
                        />
                        <b>Available rules :</b>     require, requireIf(condition), requireTrue, requireTrueIf(condition), requireNotEmpty, numeric, range(min,max), integer, unique, length(length), lengthGreater(length), lengthLess(length), telephone, email, regex(regex), idcard, DateFuture, DatetimeFuture, DateHappen, DatetimeHappen, DateAfter(date), DateBefore(Date), DateEqual(date)
                      </v-col>
                    </v-row>
                  </v-container>
                </v-expansion-panel-text>
              </v-expansion-panel>
              <v-expansion-panel v-if="!notRequireAdvancedSetting.includes(data.inputType)">
                <v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Advanced settings</v-expansion-panel-title>
                <v-expansion-panel-text>
                  <v-container fluid>
                    <v-row density="compact">
                      <v-col cols="12" md="6" v-if="!notRequireInputAttributes.includes(data.inputType)">
                        <v-text-field
                            v-model="data.inputAttributes"
                            label="Input Attributes"
                        />
                      </v-col>
                      <v-col cols="12" md="6" v-if="!notRequireColumnAttributes.includes(data.inputType)">
                        <v-text-field
                            v-model="data.columnAttributes"
                            label="Column Attributes"
                        />
                      </v-col>
                      <v-col cols="12" md="6">
                        <v-text-field
                            v-model="data.conditionalDisplay"
                            label="Conditional Display"
                        />
                      </v-col>
                      <v-col cols="12" md="6">
                        <v-text-field
                            v-model="data.computedValue"
                            label="Computed Value"
                        />
                      </v-col>
                      <v-col cols="12" md="6">
                        <v-text-field
                            v-model="data.retrievedValue"
                            label="Retrieved Value"
                        />
                      </v-col>
                    </v-row>
                  </v-container>
                </v-expansion-panel-text>
              </v-expansion-panel>
              <v-expansion-panel v-if="!notRequireClassAndStyle.includes(data.inputType)">
                <v-expansion-panel-title collapse-icon="mdi mdi-minus" expand-icon="mdi mdi-plus" class="font-weight-bold">Class and Styles</v-expansion-panel-title>
                <v-expansion-panel-text>
                  <v-container fluid>
                    <v-row density="compact">
                      <v-col cols="12">
                        <v-text-field
                            v-model="data.customClass"
                            label="Custom Class"
                        />
                      </v-col>
                      <v-col cols="12">
                        <v-text-field
                            v-model="data.customStyle"
                            label="Custom Styles"
                        />
                      </v-col>
                    </v-row>
                  </v-container>
                </v-expansion-panel-text>
              </v-expansion-panel>
            </v-expansion-panels>
          </v-col>
        </v-row>
      </v-container>
    </template>
    <template #item.configuration="props">
      <v-sheet
          elevation="1"
          max-height="250"
          class="overflow-y-auto my-1 pa-2"
          v-if="props.item.inputType == 'CustomCode' || props.item.validationRules || props.item.inputOptions || props.item.inputAttributes || props.item.columnAttributes || props.item.conditionalDisplay || props.item.computedValue || props.item.retrievedValue"
      >
        <template v-if="props.item.inputType == 'CustomCode'">
          <b>Custom Code :</b><br>
          <span style="white-space: pre-line">{{ props.item.inputCustomCode }}</span>
        </template>
        <template v-if="props.item.validationRules">
          <b>Validation Rules :</b> {{ props.item.validationRules }}<br>
        </template>
        <template v-if="props.item.inputOptions">
          <b>Input Options :</b>
          <vue-json-pretty :data="safeParseJSONDeep(props.item.inputOptions)" />
        </template>
        <template v-if="props.item.inputAttributes">
          <b>Input Attributes :</b> {{ props.item.inputAttributes }}<br>
        </template>
        <template v-if="props.item.columnAttributes">
          <b>Column Attributes :</b> {{ props.item.columnAttributes }}<br>
        </template>
        <template v-if="props.item.conditionalDisplay">
          <b>Conditional Display :</b> {{ props.item.conditionalDisplay }}<br>
        </template>
        <template v-if="props.item.computedValue">
          <b>Computed Value :</b> {{ props.item.computedValue }}<br>
        </template>
        <template v-if="props.item.retrievedValue">
          <b>Retrieved Value :</b> {{ props.item.retrievedValue }}<br>
        </template>
      </v-sheet>
    </template>
  </FormTable>
  <FormCodeEditor
      v-else
      v-model="advanceModeCode"
  />
</template>
