<script setup lang="ts">
import { useMutation, useQuery } from '@vue/apollo-composable';
import {
  CreateMyDeliveryAddressDocument,
  DeleteMyDeliveryAddressDocument,
  MyDeliveryAddressesDocument,
  SetMyDefaultDeliveryAddressDocument,
  type MyDeliveryAddressesQuery,
} from '~/composables/graphql/generated';

type AddressSuggestion = {
  value: string;
  unrestricted_value?: string;
  data?: {
    fias_id?: string;
  };
};

type DeliveryAddressItem = MyDeliveryAddressesQuery['myDeliveryAddresses'][number];

const addressFeedback = ref('');
const addressFeedbackTone = ref<'success' | 'error'>('success');

const deliveryAddressesQuery = useQuery(MyDeliveryAddressesDocument);
const createAddressMutation = useMutation(CreateMyDeliveryAddressDocument, { throws: 'never' });
const setDefaultAddressMutation = useMutation(SetMyDefaultDeliveryAddressDocument, { throws: 'never' });
const deleteAddressMutation = useMutation(DeleteMyDeliveryAddressDocument, { throws: 'never' });

const addressForm = reactive({
  label: '',
  address: '',
  unrestrictedValue: '',
  fiasId: '',
});
const addressSearch = ref('');
const addressSuggestions = ref<AddressSuggestion[]>([]);
const addressLoading = ref(false);
const addressOpen = ref(false);
const addressSearchTimer = ref<ReturnType<typeof setTimeout> | null>(null);
const addressBusyId = ref<string | null>(null);
const addressDropdownRef = ref<HTMLElement | null>(null);

const deliveryAddresses = computed<DeliveryAddressItem[]>(() => deliveryAddressesQuery.result.value?.myDeliveryAddresses ?? []);

function clearAddressTimer() {
  if (!addressSearchTimer.value) {
    return;
  }
  clearTimeout(addressSearchTimer.value);
  addressSearchTimer.value = null;
}

async function fetchAddressSuggestions() {
  const query = addressSearch.value.trim();
  if (query.length < 2) {
    addressSuggestions.value = [];
    addressOpen.value = false;
    return;
  }

  addressLoading.value = true;
  await $fetch<{ suggestions: AddressSuggestion[] }>('/api/dadata/address', {
    method: 'POST',
    body: { query },
  })
    .then((response) => {
      addressSuggestions.value = response.suggestions || [];
      addressOpen.value = addressSuggestions.value.length > 0;
    })
    .finally(() => {
      addressLoading.value = false;
    });
}

function scheduleAddressSuggest() {
  clearAddressTimer();
  addressSearchTimer.value = setTimeout(() => {
    void fetchAddressSuggestions();
  }, 250);
}

function applyAddressSuggestion(item: AddressSuggestion) {
  addressOpen.value = false;
  addressSearch.value = item.value;
  addressForm.address = item.value;
  addressForm.unrestrictedValue = item.unrestricted_value || item.value;
  addressForm.fiasId = item.data?.fias_id || '';
}

function closeDropdownsFromOutside(event: MouseEvent) {
  const target = event.target as Node | null;
  if (addressDropdownRef.value && target && !addressDropdownRef.value.contains(target)) {
    addressOpen.value = false;
  }
}

async function addDeliveryAddress() {
  addressFeedback.value = '';

  const normalizedAddress = addressForm.address.trim() || addressSearch.value.trim();
  if (normalizedAddress.length < 5) {
    addressFeedbackTone.value = 'error';
    addressFeedback.value = 'Введите адрес через подсказки DaData.';
    return;
  }

  const result = await createAddressMutation.mutate({
    input: {
      label: addressForm.label.trim() ? addressForm.label.trim() : null,
      address: normalizedAddress,
      unrestrictedValue: addressForm.unrestrictedValue.trim() ? addressForm.unrestrictedValue.trim() : null,
      fiasId: addressForm.fiasId.trim() ? addressForm.fiasId.trim() : null,
    },
  });

  const payload = result?.data?.createMyDeliveryAddress;
  if (!payload) {
    addressFeedbackTone.value = 'error';
    addressFeedback.value = createAddressMutation.error.value?.message || 'Не удалось добавить адрес.';
    return;
  }

  addressForm.label = '';
  addressForm.address = '';
  addressForm.unrestrictedValue = '';
  addressForm.fiasId = '';
  addressSearch.value = '';
  addressSuggestions.value = [];
  addressOpen.value = false;

  addressFeedbackTone.value = 'success';
  addressFeedback.value = 'Адрес сохранён.';
  await deliveryAddressesQuery.refetch();
}

async function setDefaultAddress(addressId: string) {
  addressFeedback.value = '';
  addressBusyId.value = addressId;

  const result = await setDefaultAddressMutation.mutate({ addressId });
  const payload = result?.data?.setMyDefaultDeliveryAddress;
  addressBusyId.value = null;

  if (!payload) {
    addressFeedbackTone.value = 'error';
    addressFeedback.value = setDefaultAddressMutation.error.value?.message || 'Не удалось сделать адрес основным.';
    return;
  }

  addressFeedbackTone.value = 'success';
  addressFeedback.value = 'Основной адрес обновлён.';
  await deliveryAddressesQuery.refetch();
}

async function deleteAddress(addressId: string) {
  addressFeedback.value = '';
  addressBusyId.value = addressId;

  const result = await deleteAddressMutation.mutate({ addressId });
  const payload = result?.data?.deleteMyDeliveryAddress;
  addressBusyId.value = null;

  if (!payload) {
    addressFeedbackTone.value = 'error';
    addressFeedback.value = deleteAddressMutation.error.value?.message || 'Не удалось удалить адрес.';
    return;
  }

  addressFeedbackTone.value = 'success';
  addressFeedback.value = 'Адрес удалён.';
  await deliveryAddressesQuery.refetch();
}

onMounted(() => {
  document.addEventListener('click', closeDropdownsFromOutside);
});

onBeforeUnmount(() => {
  document.removeEventListener('click', closeDropdownsFromOutside);
  clearAddressTimer();
});
</script>

<template>
  <section class="space-y-6">
    <NuxtLink to="/profile" class="link link-hover text-sm">← Назад в профиль</NuxtLink>
    <h1 class="text-3xl font-extrabold text-[#0f2f20]">Адреса доставки</h1>

    <div class="surface-card rounded-3xl p-5">
      <p class="text-sm text-[#355947]">
        Добавьте адрес через DaData и выберите основной. Этот адрес будет использоваться по умолчанию в корзине.
      </p>

      <fieldset class="fieldset mt-4">
        <legend class="fieldset-legend">Название адреса (необязательно)</legend>
        <input v-model="addressForm.label" type="text" class="input input-bordered w-full" placeholder="Склад МСК" >
      </fieldset>

      <div ref="addressDropdownRef" class="relative mt-2">
        <fieldset class="fieldset">
          <legend class="fieldset-legend">Поиск адреса (DaData)</legend>
          <input
            v-model="addressSearch"
            type="text"
            class="input input-bordered w-full"
            placeholder="Начните вводить адрес"
            @input="scheduleAddressSuggest"
            @focus="addressOpen = addressSuggestions.length > 0"
          >
        </fieldset>

        <span v-if="addressLoading" class="loading loading-spinner loading-sm absolute right-3 top-1/2 -translate-y-1/2" />

        <div
          v-if="addressOpen && addressSuggestions.length > 0"
          class="absolute z-30 mt-2 max-h-72 w-full overflow-auto rounded-box border border-base-300 bg-base-100 p-2 shadow-xl"
        >
          <button
            v-for="item in addressSuggestions"
            :key="`${item.value}-${item.data?.fias_id || ''}`"
            type="button"
            class="btn btn-ghost mb-1 h-auto min-h-0 w-full justify-start whitespace-normal px-3 py-2 text-left"
            @click="applyAddressSuggestion(item)"
          >
            <span class="block text-sm font-semibold">{{ item.value }}</span>
          </button>
        </div>
      </div>

      <button class="btn btn-primary mt-4 w-full" :disabled="createAddressMutation.loading.value" @click="addDeliveryAddress">
        {{ createAddressMutation.loading.value ? 'Добавляем…' : 'Добавить адрес' }}
      </button>

      <div v-if="addressFeedback" class="alert mt-3" :class="addressFeedbackTone === 'success' ? 'alert-success' : 'alert-error'">
        {{ addressFeedback }}
      </div>
    </div>

    <div class="surface-card rounded-3xl p-5">
      <h2 class="text-xl font-bold text-[#123824]">Список адресов</h2>

      <div class="mt-4 space-y-2">
        <div v-if="deliveryAddressesQuery.loading.value" class="alert surface-card border-0">Загрузка адресов...</div>
        <div v-else-if="deliveryAddresses.length === 0" class="alert surface-card border-0">
          Пока нет адресов доставки.
        </div>

        <article
          v-for="address in deliveryAddresses"
          :key="address.id"
          class="rounded-2xl border border-[#d6ebde] bg-white/75 p-3"
        >
          <div class="flex items-start justify-between gap-2">
            <div>
              <p class="font-semibold text-[#123824]">{{ address.label || 'Адрес доставки' }}</p>
              <p class="text-sm text-[#355947]">{{ address.unrestrictedValue || address.address }}</p>
            </div>
            <span v-if="address.isDefault" class="badge badge-success">Основной</span>
          </div>

          <div class="mt-3 flex flex-wrap gap-2">
            <button
              v-if="!address.isDefault"
              class="btn btn-sm"
              :disabled="addressBusyId === address.id"
              @click="setDefaultAddress(address.id)"
            >
              {{ addressBusyId === address.id ? 'Сохраняем…' : 'Сделать основным' }}
            </button>
            <button
              class="btn btn-sm btn-ghost text-error"
              :disabled="addressBusyId === address.id"
              @click="deleteAddress(address.id)"
            >
              {{ addressBusyId === address.id ? 'Удаляем…' : 'Удалить' }}
            </button>
          </div>
        </article>
      </div>
    </div>
  </section>
</template>
