<template>
  <q-dialog :model-value="conditionModal">
    <q-card class="loyalty-suite-form__conditions-modal">
      <q-inner-loading :showing="loading">
        <q-spinner color="primary" size="70px" />
      </q-inner-loading>

      <q-form class="loyalty-suite-form" @submit="applyConditionsData">
        <q-card-section v-if="!loading">
          <template v-for="field in conditionsFields" :key="field.key">
            <div v-if="shouldShowField(field)" class="loyalty-suite-form__row loyalty-suite-form__row_full-width">
              <span class="loyalty-suite-form__row-label">
                {{ $t(field.key) }}
                <span
                  v-if="['purchase_amount'].includes(tempConditionsData.condition?.value) && field.type === 'goal'"
                  class="loyalty-suite-form__row-label-currency">
                  , {{ currency['symbol'] }}
                </span>
                <span v-if="requiredFields.includes(field.key)" class="loyalty-suite-form__row-label-required">*</span>
                <q-icon name="info_outline" size="18px" class="loyalty-suite-form__row-hint">
                  <q-tooltip anchor="top right" self="top right">
                    {{ uniqueLabels.includes(field.key) ? $t(`use_${field.key}`) : $t(`in_${field.key}`) }}
                  </q-tooltip>
                </q-icon>
              </span>

              <q-select v-if="field.type === 'primary'" v-model="tempConditionsData[field.key]"
                :options="filteredOptions[field.key] || field.options" option-disable="disabled" use-input hide-selected
                fill-input input-debounce="0"
                :rules="requiredFields.includes(field.key) ? [() => !!tempConditionsData[field.key] || $t('requiredField')] : []"
                :placeholder="$t('selectValue')" @filter="(val, update) => filterOptions(val, update, field)" outlined
                @update:model-value="(val) => {
                  if ((val?.__pro && !isPro) || (val?.__wc && !isWoo)) {
                    tempConditionsData[field.key] = null;
                  }
                }"
              >
                <template v-slot:no-option>
                  <q-item>
                    <q-item-section class="text-grey">{{ $t('noResultsFound') }}</q-item-section>
                  </q-item>
                </template>

                <template v-slot:option="scope">
                  <q-item
                    v-bind="(scope.opt.__pro && !isPro) || (scope.opt.__wc && !isWoo)
                      ? { ...scope.itemProps, onClick: undefined }
                      : scope.itemProps"
                    :class="{
                      'loyalty-suite-form__pro-field': scope.opt.__pro && !isPro,
                      'loyalty-suite-form__wc-field':  scope.opt.__wc && !isWoo
                    }"
                  >
                    <q-item-section>
                      <q-item-label>{{ scope.opt.label }}</q-item-label>
                      <q-badge v-if="scope.opt.__pro && !isPro" color="positive" label="PRO" />
                    </q-item-section>
                    <q-item-section v-if="!scope.opt.disabled" side>
                      <q-icon name="info_outline" class="loyalty-suite-form__select-info" size="18px">
                        <q-tooltip anchor="top right" self="top right">
                          {{ $t(`opt_${scope.opt.value}`) }}
                        </q-tooltip>
                      </q-icon>
                    </q-item-section>
                  </q-item>
                </template>
              </q-select>

              <q-select v-else-if="field.type === 'single'" v-model="tempConditionsData[field.key]"
                :options="filteredOptions[field.key] || field.options" option-disable="disabled" use-input hide-selected
                fill-input input-debounce="0"
                :rules="requiredFields.includes(field.key) ? [() => !!tempConditionsData[field.key] || $t('requiredField')] : []"
                :placeholder="$t('selectValue')" @filter="(val, update) => filterOptions(val, update, field)" outlined>
                <template v-slot:no-option>
                  <q-item>
                    <q-item-section class="text-grey">{{ $t('noResultsFound') }}</q-item-section>
                  </q-item>
                </template>
              </q-select>

              <q-select class="loyalty-suite-simple-select" v-else-if="field.type === 'simple_select'"
                v-model="tempConditionsData[field.key]" :options="filteredOptions[field.key] || field.options"
                option-disable="disabled" input-debounce="0"
                :rules="requiredFields.includes(field.key) ? [() => !!tempConditionsData[field.key] || $t('requiredField')] : []"
                :placeholder="$t('selectValue')" @filter="(val, update) => filterOptions(val, update, field)" outlined>
                <template v-slot:no-option>
                  <q-item>
                    <q-item-section class="text-grey">{{ $t('noResultsFound') }}</q-item-section>
                  </q-item>
                </template>
              </q-select>

              <q-select v-else-if="field.type === 'multiselect'" v-model="tempConditionsData[field.key]"
                :options="filteredOptions[field.key] || field.options" option-disable="disabled" use-input fill-input
                use-chips multiple input-debounce="0"
                :rules="requiredFields.includes(field.key) ? [() => !!tempConditionsData[field.key] || $t('requiredField')] : []"
                :placeholder="$t('selectValue')" @filter="(val, update) => filterOptions(val, update, field)"
                @update:model-value="checkMultiSelect(field.key)" outlined>
                <template v-slot:no-option>
                  <q-item>
                    <q-item-section class="text-grey">{{ $t('noResultsFound') }}</q-item-section>
                  </q-item>
                </template>
              </q-select>

              <q-select v-else-if="field.type === 'dependency_single'" v-model="tempConditionsData[field.key]"
                :options="filteredOptions[field.key] || field.options" option-disable="disabled" use-input fill-input
                hide-selected outlined
                :rules="requiredFields.includes(field.key) ? [() => !!tempConditionsData[field.key] || $t('requiredField')] : []"
                :placeholder="$t('selectValue')" :loading="loadingStates[field.key]">
                <template v-slot:no-option>
                  <q-item>
                    <q-item-section class="text-grey">{{ $t('noResultsFound') }}</q-item-section>
                  </q-item>
                </template>
              </q-select>

              <q-select v-else-if="field.type === 'api_multiselect'" v-model="tempConditionsData[field.key]"
                :options="filteredOptions[field.key] || field.options" option-disable="disabled" use-chips use-input
                fill-input multiple input-debounce="300" :placeholder="$t('enterValue')"
                :rules="requiredFields.includes(field.key) ? [() => !!tempConditionsData[field.key] || $t('requiredField')] : []"
                @filter="(val, update) => fetchOptions(val, update, field)"
                @update:model-value="checkMultiSelect(field.key)" outlined>
                <template v-slot:no-option>
                  <q-item v-if="!isFiltering && searchQuery.length >= 2">
                    <q-item-section class="text-grey">{{ $t('noResultsFound') }}</q-item-section>
                  </q-item>
                </template>
              </q-select>

              <q-input v-else-if="field.type === 'goal'" v-model="tempConditionsData.goal" type="number"
                @update:model-value="tempConditionsData.goal = formatNumber(tempConditionsData.goal)"
                :placeholder="$t('enterValue')"
                :rules="[() => !!tempConditionsData.goal || $t('requiredField')]" outlined />


              <q-input v-else-if="field.type === 'text_input'" v-model="tempConditionsData[field.key]" type="text"
                :placeholder="$t('enterValue')" :rules="[
                  () => !!tempConditionsData[field.key] || $t('requiredField'),
                  validateUrl
                ]" outlined />

              <q-input v-else-if="field.type === 'textarea'" v-model="tempConditionsData[field.key]" type="textarea"
                class="loyalty-suite-form__textarea" :placeholder="$t('enterValue')"
                :rules="[() => !!tempConditionsData[field.key] || $t('requiredField')]" outlined :rows="5" />

            </div>
          </template>
        </q-card-section>

        <q-card-actions v-if="!loading" align="center">
          <q-btn :label="$t('cancel')" color="negative" @click="resetForm" />
          <q-btn type="submit" :label="initialData ? $t('edit') : $t('add')" color="primary" />
        </q-card-actions>
      </q-form>
    </q-card>
  </q-dialog>
</template>

<script lang="ts">
import { defineComponent, ref, watch, toRaw, nextTick } from 'vue';
import { useI18n } from 'vue-i18n';

export default defineComponent({
  props: {
    conditionModal: {
      type: Boolean,
      required: true,
    },
    initialData: {
      type: Object as () => Record<string, any> | null,
      default: null,
    },
    conditionsFields: {
      type: Array as () => Array<{ key: string; type: string; options?: { value: string; label: string }[]; dependency?: string[] }>,
      required: true,
    },
    requiredFields: {
      type: Array,
      required: true,
    },
    loading: {
      type: Boolean,
      required: true,
    },
    currency: {
      type: Array,
      required: true,
    },
  },
  emits: ['update:conditionModal', 'add-condition', 'update-condition'],
  setup(props, { emit }) {
    const apiRoutes = window.loyalty_suite_admin_data.apiRoutes;
    const nonce = window.loyalty_suite_admin_data.nonce;
    const tempConditionsData = ref<Record<string, any>>({});
    const loadingStates = ref<Record<string, boolean>>({});
    const isPro = window.loyalty_suite_admin_data.isPro;
    const isWoo = window.loyalty_suite_admin_data.isWooEnabled;
    const searchQuery = ref('');
    const isFiltering = ref(false);
    const { t } = useI18n();
    const uniqueLabels = [
      'condition',
      'goal',
      'network',
      'social_link',
      'shared_link',
      'publish_content_desc',
      'network_verification',
      'refer_link_purchase',
      'refer_link_signup'
    ];

    const shouldShowField = (field: any): boolean => {
      if (!Array.isArray(field.dependency) || field.dependency.length === 0) {
        return true;
      }

      const conditionsData = tempConditionsData.value || {};

      return field.dependency.every((dep: any) => {
        if (!dep || typeof dep !== 'object' || !dep.key) {
          return false;
        }

        const conditionValue = conditionsData[dep.key];

        if (Array.isArray(dep.value)) {
          return conditionValue !== undefined && dep.value.includes(conditionValue?.value);
        }

        if (dep.value === true) {
          return conditionValue !== null && conditionValue !== undefined;
        }

        return false
      });
    };

    const formatNumber = (value: number | string | null): number | null => {
      if (value === null || value === '' || isNaN(Number(value))) {
        return null;
      }

      const numberValue = Math.round(Number(value));

      return numberValue > 0 ? numberValue : null;
    };

    const validateUrl = (value: string) => {
      if (!value) return true;

      try {
        const url = new URL(value);
        return true;
      } catch (error) {
        return t('correctUrl');
      }
    };

    const filteredOptions = ref<Record<string, { value: string; label: string; disabled?: boolean }[]>>({});

    const filterOptions = (
      val: string,
      update: (callback: () => void) => void,
      field: { key: string; options?: { value: string; label: string; disabled?: boolean }[] }
    ) => {
      let fieldOptions = field.options ?? [];

      if (field.key === 'network' && tempConditionsData.value?.condition.value === 'share_on') {
        fieldOptions = fieldOptions.filter(
          opt => opt.value !== 'youtube' && opt.value !== 'instagram'
        );
      }

      update(() => {
        filteredOptions.value[field.key] = val
          ? fieldOptions.filter(option => !option.disabled && option.label.toLowerCase().includes(val.toLowerCase()))
          : [...fieldOptions];
      });
    };

    const fetchOptions = async (val: string, update: (callback: () => void) => void, field: any) => {
      searchQuery.value = val;

      if (!val) {
        filteredOptions.value[field.key] = [];
        isFiltering.value = false;
        update(() => { });
        return;
      }

      isFiltering.value = true;

      try {
        const buildApiUrl = (base, params = {}) => {
          const url = new URL(base, window.location.origin);
          Object.entries(params).forEach(([k, v]) => {
            if (v !== undefined && v !== null && v !== '') url.searchParams.set(k, v);
          });
          return url.toString();
        };

        const response = await fetch(
          buildApiUrl(apiRoutes.admin[field.key], { identifier: val }),
          {
            method: 'GET',
            headers: {
              'X-WP-Nonce': nonce,
              'Content-Type': 'application/json',
            },
            credentials: 'same-origin',
          }
        );

        if (!response.ok) {
          return [];
        }

        const data = await response.json();

        update(() => {
          filteredOptions.value[field.key] = Array.isArray(data) ? data : []
          isFiltering.value = false;
        });
      } catch (error) {
        console.error(t('couldNotFetchData'), error);
        filteredOptions.value[field.key] = [];
        update(() => {
          filteredOptions.value[field.key] = [];
          isFiltering.value = false;
        });
      }
    };

    const checkMultiSelect = (key: string) => {
      if (Array.isArray(tempConditionsData.value[key]) && tempConditionsData.value[key].length === 0) {
        tempConditionsData.value[key] = null;
      }
    };

    watch(
      () => tempConditionsData.value.condition,
      async (newCondition) => {
        if (!newCondition) return;

        const conditionValue = newCondition;

        tempConditionsData.value = {};
        tempConditionsData.value.condition = conditionValue;

        props.conditionsFields.forEach(field => {
          if (!shouldShowField(field)) return;
          if (Array.isArray(field.options) && typeof field.options[0] === 'object') {
            const options = filteredOptions.value[field.key] || field.options || [];
            const defaultOption = options.find(opt => opt.value === field.default);
            if (defaultOption) {
              tempConditionsData.value[field.key] = defaultOption;
            }
          } else {
            tempConditionsData.value[field.key] = field.default;
          }
        })

        await nextTick();
        Object.keys(tempConditionsData.value).forEach((key) => {
          checkMultiSelect(key);
        });
      }
    );

    watch(
      () => props.initialData,
      async (newData) => {
        if (!newData) {
          tempConditionsData.value = {};
          return;
        }

        if (newData.condition) {
          tempConditionsData.value.condition = JSON.parse(JSON.stringify(newData.condition));
        }

        await nextTick();

        Object.keys(newData).forEach((key) => {
          if (key !== "condition") {
            tempConditionsData.value[key] = JSON.parse(JSON.stringify(newData[key]));
          }
        });

        Object.keys(tempConditionsData.value).forEach((key) => {
          checkMultiSelect(key);
        });
      },
      { deep: true, immediate: true }
    );

    const resetForm = async () => {
      emit('update:conditionModal', false);
      await nextTick();

      if (!props.initialData) {
        tempConditionsData.value = {};
      }
    };

    const applyConditionsData = () => {
      const rawData = toRaw(tempConditionsData.value);
      const updatedData = props.initialData ? { ...props.initialData } : {};

      Object.keys(updatedData).forEach((key) => {
        if (key !== 'condition') {
          delete updatedData[key];
        }
      });

      Object.assign(updatedData, rawData);

      if (props.initialData) {
        emit('update-condition', updatedData);
      } else {
        emit('add-condition', updatedData);
      }

      emit('update:conditionModal', false);
      tempConditionsData.value = {};
    };

    return {
      tempConditionsData,
      formatNumber,
      filterOptions,
      fetchOptions,
      filteredOptions,
      checkMultiSelect,
      loadingStates,
      resetForm,
      applyConditionsData,
      shouldShowField,
      validateUrl,
      uniqueLabels,
      searchQuery,
      isFiltering,
      isPro,
      isWoo
    };
  },
});
</script>
