<template>
  <div class="store">
    <store-filter
        v-if="filters.length"
        :filterableAttributes="filters"
        :isOpen="showFilter"
        @update:selected="onFiltersChange"
        @close="showFilter = false"
    />
    <div class="store__inner">
      <store-top
          v-model="orderBy"
          @toggle-filter="onFilterToggle"
          :isFilters="filters.length > 0"
      />
      <client-only>
        <div
            class="store__list"
            :class="[
              { 'store__list-grid': productView === 'grid' },
              { 'store__list-list': productView === 'list' }
            ]"
        >
          <cards-product
              v-if="products.length && !pending"
              v-for="product in products"
              :key="product.node.uuid"
              :product="product.node"
              :isList="productView === 'list'"
          />
          <skeletons-cards-product
              v-if="pending"
              v-for="idx in 12"
              :key="idx"
              :isList="productView === 'list'"
          />
        </div>
      </client-only>
      <div class="store__list-observer" ref="observer"></div>
      <p class="store__empty" v-if="!products.length && !pending">{{ t('store.empty') }}</p>
    </div>
  </div>
</template>

<script setup lang="ts">
import {useFilters, useStore} from '@composables/store';
import {useCategoryBySlug} from '@composables/categories';
import {useBrandBySlug} from '@composables/brands';
import {useDefaultSeo} from '@composables/seo';

const { t, locale } = useI18n();
const { $appHelpers } = useNuxtApp();

const productView = useCookie<string>(
  $appHelpers.COOKIES_PRODUCT_VIEW_KEY as string,
  {
    default: () => 'grid',
    path: '/',
  }
);

const categorySlug = useRouteParams<string>('categorySlug');
const brandSlug = useRouteParams<number>('brandSlug');
const attributes = useRouteQuery<string>('attributes', '');
const orderBy = useRouteQuery<string>('orderBy', 'created');
const minPrice = useRouteQuery<number>('minPrice', 0);
const maxPrice = useRouteQuery<number>('maxPrice', 50000);
const observer = ref(null);

const categoryData = categorySlug.value
    ? await useCategoryBySlug(categorySlug.value)
    : { category: ref(null), seoMeta: ref(null), filters: ref([]) };

const brandData = brandSlug.value
    ? await useBrandBySlug(brandSlug.value)
    : { brand: ref(null), seoMeta: ref(null) };

const { category, seoMeta: categorySeoMeta, filters } = categoryData;
const { brand, seoMeta: brandSeoMeta } = brandData;

const seoMeta = computed(() => categorySeoMeta.value || brandSeoMeta.value);

const meta = useDefaultSeo(seoMeta.value || null);

if (meta) {
  useSeoMeta({
    title: meta.title || $appHelpers.APP_NAME,
    description: meta.description || meta.title || $appHelpers.APP_NAME,
    ogTitle: meta.og.title || undefined,
    ogDescription: meta.og.description || meta.title || $appHelpers.APP_NAME,
    ogType: meta.og.type || undefined,
    ogUrl: meta.og.url || undefined,
    ogImage: meta.og.image || undefined,
    twitterCard: meta.twitter.card || undefined,
    twitterTitle: meta.twitter.title || undefined,
    twitterDescription: meta.twitter.description || undefined,
    robots: meta.robots,
  });

  useHead({
    link: [
      meta.canonical ? { rel: 'canonical', href: meta.canonical } : {},
    ].filter(Boolean) as any,
    meta: [{ property: 'og:locale', content: locale.value }],
    script: meta.jsonLd.map((obj: any) => ({
      type: 'application/ld+json',
      innerHTML: JSON.stringify(obj),
    })),
    __dangerouslyDisableSanitizersByTagID: Object.fromEntries(
        meta.jsonLd.map((_, i: number) => [`ldjson-${i}`, ['innerHTML']])
    ),
  });
}

watch(
  () => category.value,
  (cat) => {
    if (cat && !useRoute().query.maxPrice) {
      maxPrice.value = cat.minMaxPrices.maxPrice;
    }
  },
  { immediate: true }
);

const { pending, products, pageInfo, variables, getProducts } = useStore({
  orderBy: orderBy.value,
  categoriesSlugs: categorySlug.value,
  productAfter: '',
  minPrice: minPrice.value,
  maxPrice: maxPrice.value,
  brand: brand.value?.name,
  attributes: attributes.value
});
await getProducts();

const { buildAttributesString } = useFilters(filters);
const showFilter = ref<boolean>(false);

function onFilterToggle() {
  showFilter.value = true;
}

async function onFiltersChange(newFilters: Record<string, string[]>) {
  const attrString = buildAttributesString(newFilters);
  attributes.value = attrString;
  variables.attributes = attrString;
  await getProducts();
}

useIntersectionObserver(
  observer,
  async ([{ isIntersecting }]) => {
    if (isIntersecting && pageInfo.value?.hasNextPage && !pending.value) {
      variables.productAfter = pageInfo.value.endCursor;
      await getProducts();
    }
  },
);

watch(orderBy, async (newVal) => {
  variables.orderBy = newVal || '';
  variables.productAfter = '';
  products.value = [];
  await getProducts();
});
watch(attributes, async (newVal) => {
  variables.attributes = newVal;
  variables.productAfter = '';
  products.value = [];
  await getProducts();
});
watch(minPrice, async (newVal) => {
  variables.minPrice = newVal || 0;
  variables.productAfter = '';
  products.value = [];
  await getProducts();
});
watch(maxPrice, async (newVal) => {
  variables.maxPrice = newVal || 500000;
  variables.productAfter = '';
  products.value = [];
  await getProducts();
});
</script>

<style scoped lang="scss">
.store {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 32px;

  &__inner {
    width: 100%;
  }

  &__list {
    margin-top: 50px;

    &-grid {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
      gap: 25px;
    }

    &-list {
      display: flex;
      flex-direction: column;
      align-items: stretch;
      gap: 20px;
    }

    &-observer {
      background-color: transparent;
      width: 100%;
      height: 10px;
    }
  }

  &__empty {
    color: $primary;
    font-weight: 500;
    font-size: 18px;
  }
}
</style>