<template>
  <q-scroll-area class="loyalty-suite-wrapper">
    <q-inner-loading :showing="loading">
      <q-spinner color="primary" size="70px" />
    </q-inner-loading>

    <template v-if="!loading">
      <div v-if="error" class="loyalty-suite-api-error-message">
        <q-icon name="error_outline" color="negative" size="md" />
        <span>{{ error }}</span>
      </div>
      <template v-else>
        <div class="loyalty-suite-transaction">
          <div class="loyalty-suite-transaction__title">
            <q-btn icon="arrow_back" color="primary" class="loyalty-suite-form__back" @click="goBack" />
            <h1 class="loyalty-suite-transaction__title-text">
              {{ $t('transactionAdd') }}
            </h1>
          </div>
          <q-form class="loyalty-suite-form" @submit.prevent="submitForm">
            <div class="loyalty-suite-form__section">
              <div class="loyalty-suite-form__title">
                {{ $t('mainSettings') }}
              </div>

              <div class="loyalty-suite-form__row">
                <span class="loyalty-suite-form__row-label">
                  {{ $t('transactionWallet') }}
                  <span class="loyalty-suite-form__row-label-required">*</span>
                </span>
                <q-select v-model="selectedWallet" :options="wallets" fill-input input-debounce="0"
                  :rules="[() => !!selectedWallet || $t('requiredField')]" outlined>
                </q-select>
              </div>

              <div class="loyalty-suite-form__row">
                <span class="loyalty-suite-form__row-label">
                  {{ $t('transactionUser') }}
                  <span class="loyalty-suite-form__row-label-required">*</span>
                </span>
                <q-select
                  class="loyalty-suite-form__api-select"
                  :class="{ 'loyalty-suite-form__api-select_selected': !!transaction.user }"
                  v-model="transaction.user"
                  :options="userOptions" option-disable="disabled" use-input
                  use-chips map-options emit-value outlined
                  fill-input input-debounce="300" :placeholder="$t('enterUserValue')"
                  :rules="[() => !!transaction.user || $t('requiredField')]"
                  @filter="(val, update) => fetchOptions(val, update)">
                  <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>
              </div>

              <div class="loyalty-suite-form__row">
                <span class="loyalty-suite-form__row-label">
                  {{ $t('transactionType') }}
                  <q-icon name="info_outline" size="18px" class="loyalty-suite-form__row-hint">
                    <q-tooltip anchor="top right" self="top right">
                      {{ $t('transactionTypeHint') }}
                    </q-tooltip>
                  </q-icon>
                </span>
                <q-select v-model="selectedTransactionType" :options="transactionTypeOptions" fill-input input-debounce="0"
                  :rules="[() => !!selectedTransactionType || $t('requiredField')]" outlined>
                </q-select>
              </div>

              <div class="loyalty-suite-form__row">
                <span class="loyalty-suite-form__row-label">
                  {{ $t('transactionAmount') }}
                  <span 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">
                      {{ $t('transactionAmountHint') }}
                    </q-tooltip>
                  </q-icon>
                </span>
                <q-input v-model="transaction.amount" outlined type="number"
                  @update:model-value="formatFloat()" :rules="[(val: number) => val && val > 0 || $t('requiredField')]" />
              </div>
            </div>

            <div class="loyalty-suite-form__action">
              <q-btn type="submit" :label="$t('add')" :loading="changeLoading"
                color="primary" />
            </div>

            <div v-if="addError" class="loyalty-suite-form__action-error">
              {{ $t(addError) }}
            </div>

            <q-dialog v-model="confirmLeave">
              <q-card>
                <q-card-section>
                  <span>{{ $t('unsavedChanges') }}</span>
                </q-card-section>
                <q-card-actions align="center">
                  <q-btn :label="$t('cancel')" color="negative" v-close-popup />
                  <q-btn :label="$t('discardChanges')" color="primary" v-close-popup @click="navigateBack" />
                </q-card-actions>
              </q-card>
            </q-dialog>
          </q-form>
        </div>
      </template>
    </template>
  </q-scroll-area>
</template>

<script lang="ts">
import { defineComponent, ref, onBeforeMount, computed, watch } from 'vue';
import { useRouter, useRoute } from 'vue-router';
import { useI18n } from 'vue-i18n';

export default defineComponent({
  setup() {
    const router = useRouter();
    const loading = ref(true);
    const changeLoading = ref(false);
    const originalTransaction = ref<string | null>(null);
    const confirmLeave = ref(false);
    const error = ref<string | null>(null);
    const addError = ref<string | null>(null);
    const apiRoutes = window.loyalty_suite_admin_data.apiRoutes;
    const nonce = window.loyalty_suite_admin_data.nonce;
    const route = useRoute();
    const { t } = useI18n();
    const userOptions = ref<Array<{ value: string; label: string }>>([]);
    const wallets = ref([]);
    const selectedWallet = ref<{ value: number; label: string } | null>(null);
    const searchQuery = ref('');
    const isFiltering = ref(false);

    const transaction = ref<{
      user: number | null,
      wallet: number | null,
      transaction_type: string,
      amount: number | null,
    }>({
      user: null,
      wallet: null,
      transaction_type: '',
      amount: null,
    });

    const goBack = () => {
      if (isDirty.value) {
        confirmLeave.value = true;
        return;
      }

      navigateBack();
    };

    const navigateBack = () => {
      if (window.history.length > 1) {
        router.back();
      } else {
        router.push(`/wallets/transactions/${route.query.wallet}`);
      }
    };

    const isDirty = computed(() => {
      return originalTransaction.value !== null &&
        JSON.stringify(transaction.value) !== originalTransaction.value;
    });

    watch(selectedWallet, (newVal) => {
      transaction.value.wallet = newVal?.value || null;
    });

    const transactionTypeOptions = ref([
      { value: 'credit', label: t('credit') },
      { value: 'debit', label: t('debit') }
    ]);

    const selectedTransactionType = computed({
      get: () => {
        return (
          transactionTypeOptions.value.find(option => option.value === transaction.value.transaction_type) ||
          transactionTypeOptions.value[0]
        );
      },
      set: (newValue) => {
        transaction.value.transaction_type = newValue?.value || 'credit';
      }
    });

    const formatFloat = () => {
      const value = transaction.value.amount;

      if (value === null || isNaN(Number(value)) || Number(value) === 0) {
        transaction.value.amount = null as never;
        return;
      }

      transaction.value.amount = Number(value) as never;
    };

    const submitForm = async () => {
      try {
        changeLoading.value = true;
        const formData = new FormData();

        formData.append('user', String(transaction.value.user));
        formData.append('wallet', String(transaction.value.wallet));
        formData.append('transaction_type', String(transaction.value.transaction_type));
        formData.append('amount', String(transaction.value.amount));

        const response = await fetch(apiRoutes.admin.save_transaction, {
          method: 'POST',
          headers: {
            'X-WP-Nonce': nonce
          },
          body: formData
        });

        const responseData = await response.json().catch(() => null);

        if (!responseData || responseData.error) {
          addError.value = responseData?.error || 'Unknown error';
          return;
        }

        router.push(`/wallets/transactions/${transaction.value.wallet}`);
      } catch (err) {
        addError.value = err instanceof Error ? err.message : 'Error submitting data';
      } finally {
        changeLoading.value = false;
      }
    };

    const fetchWallets = async () => {
      try {
        const response = await fetch(`${apiRoutes.admin.wallets}`, {
          method: 'GET',
          headers: {
            'X-WP-Nonce': nonce,
            'Content-Type': 'application/json',
          }
        });

        const data = await response.json().catch(() => null);

        if (!response.ok) {
          addError.value = data?.error;
          return;
        }

        wallets.value = data;
        const passedId = Number(route.query.wallet);
        const initial = wallets.value.find(option => option.value === passedId) || wallets.value[0] || null;

        selectedWallet.value = initial;
        transaction.value.wallet = initial?.value || null;
        transaction.value.transaction_type = transactionTypeOptions.value[0].value;
        originalTransaction.value = JSON.stringify(transaction.value);
      } catch (err) {
        error.value = err instanceof Error ? err.message : t('couldNotFetchData');
        console.error('API Error:', error.value);
      } finally {
        loading.value = false;
      }
    };

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

      if (!val) {
        userOptions.value = [];
        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.users, { 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(() => {
          userOptions.value = Array.isArray(data) ? data : [];
          isFiltering.value = false;
        });
      } catch (error) {
        console.error(t('couldNotFetchData'), error);
        update(() => {
          userOptions.value = [];
          isFiltering.value = false;
        });
      }
    };

    onBeforeMount(() => fetchWallets());

    return {
      changeLoading,
      addError,
      error,
      confirmLeave,
      navigateBack,
      transaction,
      formatFloat,
      loading,
      wallets,
      goBack,
      selectedWallet,
      selectedTransactionType,
      transactionTypeOptions,
      userOptions,
      fetchOptions,
      submitForm,
      isFiltering,
      searchQuery
    };
  }
});
</script>

<style lang="scss" scoped>
.loyalty-suite-transaction {
  display: flex;
  flex-direction: column;
  width: 100%;

  &__title {
    display: flex;
    align-items: center;
    width: 100%;
    margin-bottom: 25px;

    &-text {
      display: flex;
      font-size: 22px;
    }
  }

  .loyalty-suite-form {
    width: 700px;
  }
}
</style>
