<script setup lang="ts">
import { computed, onMounted, ref, watch } from "vue";
import TagsField from "./TagsField.vue";
import { pb } from "../pocketbase";
import Tag from "../models/tag";
import * as yup from "yup";
import MultiSelectField from "./MultiSelectField.vue";
import { storeToRefs } from "pinia";
import { useRestaurantsStore } from "../stores/restaurants";
import { useForm } from "vee-validate";
import { toTypedSchema } from "@vee-validate/yup";
import { makeFilters } from "../utils/filters";
import { SearchPreferences } from "../models/search";
import { usePreferencesStore } from "../stores/preferences";

const priceTicks = {
  1: "€",
  2: "€€",
  3: "€€€",
  4: "€€€€",
};

const { restaurants } = storeToRefs(useRestaurantsStore());
const { searchPreferences } = storeToRefs(usePreferencesStore());

const restaurantOptions = computed(() => {
  return restaurants.value.map((restaurant) => restaurant.id);
});

const restaurantLabels = computed(() => {
  const labels: Map<string, string> = new Map();
  restaurants.value.forEach((restaurant) => {
    labels.set(restaurant.id, restaurant.name);
  });
  return labels;
});

const availableTags = ref<Tag[]>([]);

const tagsOptions = computed(() => {
  return availableTags.value.map((tag) => tag.id);
});

const tagsLabels = computed(() => {
  const labels: Map<string, string> = new Map();
  availableTags.value.forEach((tag) => {
    labels.set(tag.id, tag.name);
  });
  return labels;
});

function mapValuesToModel(values: Object): SearchPreferences {
  return {
    priceRangeEnabled: values["priceRangeEnabled"],
    includeTagsEnabled: values["includeTagsEnabled"],
    excludeTagsEnabled: values["excludeTagsEnabled"],
    includeRestaurantsEnabled: values["includeRestaurantsEnabled"],
    excludeRestaurantsEnabled: values["excludeRestaurantsEnabled"],
    lowerPriceBound: values["priceRange"] ? priceTicks[values["priceRange"][0]!] : undefined,
    upperPriceBound: values["priceRange"] ? priceTicks[values["priceRange"][1]!] : undefined,
    includedTags: values["includedTags"],
    excludedTags: values["excludedTags"],
    includedRestaurants: values["includedRestaurants"],
    excludedRestaurants: values["excludedRestaurants"],
  };
}

const { errors, values, handleSubmit, defineField } = useForm({
  validationSchema: toTypedSchema(
    yup.object({
      priceRangeEnabled: yup.boolean(),
      includeTagsEnabled: yup.boolean(),
      excludeTagsEnabled: yup.boolean(),
      includeRestaurantsEnabled: yup.boolean(),
      excludeRestaurantsEnabled: yup.boolean(),
      priceRange: yup.array().of(yup.number()).min(2).max(2),
      includedTags: yup.array().of(yup.string()),
      excludedTags: yup.array().of(yup.string()),
      includedRestaurants: yup.array().of(yup.string()),
      excludedRestaurants: yup.array().of(yup.string()),
    })
  ),
  initialValues: {
    priceRangeEnabled: searchPreferences.value?.priceRangeEnabled,
    includeTagsEnabled: searchPreferences.value?.includeTagsEnabled,
    excludeTagsEnabled: searchPreferences.value?.excludeTagsEnabled,
    includeRestaurantsEnabled: searchPreferences.value?.includeRestaurantsEnabled,
    excludeRestaurantsEnabled: searchPreferences.value?.excludeRestaurantsEnabled,
    priceRange: [
      Number(Object.keys(priceTicks).find((key) => priceTicks[key] == searchPreferences.value?.lowerPriceBound ?? "€")),
      Number(
        Object.keys(priceTicks).find((key) => priceTicks[key] == searchPreferences.value?.upperPriceBound ?? "€€€€")
      ),
    ],
    includedTags: searchPreferences.value?.includedTags,
    excludedTags: searchPreferences.value?.excludedTags,
    includedRestaurants: searchPreferences.value?.includedRestaurants,
    excludedRestaurants: searchPreferences.value?.excludedRestaurants,
  },
});

const filteredRestaurants = ref<number>(restaurants.value.length);

watch(
  values,
  async (newval, oldval) => {
    const filters = makeFilters(mapValuesToModel(newval));
    filteredRestaurants.value = useRestaurantsStore().getFilteredRestaurants(filters).length;
  },
  { immediate: true }
);

const [priceRangeEnabled, priceRangeEnabledAttrs] = defineField("priceRangeEnabled");
const [includeTagsEnabled, includeTagsEnabledAttrs] = defineField("includeTagsEnabled");
const [excludeTagsEnabled, excludeTagsEnabledAttrs] = defineField("excludeTagsEnabled");
const [includeRestaurantsEnabled, includeRestaurantsEnabledAttrs] = defineField("includeRestaurantsEnabled");
const [excludeRestaurantsEnabled, excludeRestaurantsEnabledAttrs] = defineField("excludeRestaurantsEnabled");
const [priceRange, priceRangeAttrs] = defineField("priceRange");
const [includedTags, includedTagsAttrs] = defineField("includedTags");
const [excludedTags, excludedTagsAttrs] = defineField("excludedTags");
const [includedRestaurants, includedRestaurantsAttrs] = defineField("includedRestaurants");
const [excludedRestaurants, excludedRestaurantsAttrs] = defineField("excludedRestaurants");

onMounted(async () => {
  availableTags.value = await pb.collection("tags").getFullList();

  pb.collection("tags").subscribe("*", async (e) => {
    availableTags.value = await pb.collection("tags").getFullList();
  });
});

const emit = defineEmits({
  preferencesSaved: () => true,
});

const onSubmit = handleSubmit(async (values) => {
  try {
    const data = mapValuesToModel(values);
    console.log(values);
    await pb.collection("search_preferences").update(searchPreferences.value!.id!, data);
  } catch (err) {
    console.log(err);
  }

  emit("preferencesSaved");
});
</script>

<template>
  <div class="flex flex-col place-content-center items-center h-full">
    <div class="flex flex-row flex-nowrap w-full">
      <div class="mx-5 my-4 w-full">
        <label class="form-label mb-2">
          <input type="checkbox" v-model="priceRangeEnabled" class="checkbox border-solid" />
          Price range
        </label>
        <v-range-slider
          v-model="priceRange"
          show-ticks="always"
          :min="1"
          :max="4"
          :step="1"
          :ticks="priceTicks"
          track-size="8"
          :disabled="!priceRangeEnabled"
        />
      </div>
    </div>
    <div class="flex flex-row flex-nowrap w-full">
      <div class="mx-5 my-4 w-full">
        <label class="form-label mb-2">
          <input type="checkbox" v-model="includeTagsEnabled" class="checkbox border-solid" />
          Include tags
        </label>
        <TagsField
          v-model="includedTags"
          :create="false"
          :options="tagsOptions"
          :labels="tagsLabels"
          :disabled="!includeTagsEnabled"
        />
      </div>
    </div>
    <div class="flex flex-row flex-nowrap w-full">
      <div class="mx-5 my-4 w-full">
        <label class="form-label mb-2">
          <input type="checkbox" v-model="excludeTagsEnabled" class="checkbox border-solid" />
          Exclude tags
        </label>
        <TagsField
          v-model="excludedTags"
          :create="false"
          :options="tagsOptions"
          :labels="tagsLabels"
          :disabled="!excludeTagsEnabled"
        />
      </div>
    </div>
    <div class="flex flex-row flex-nowrap w-full">
      <div class="mx-5 my-4 w-full">
        <label class="form-label mb-2">
          <input type="checkbox" v-model="includeRestaurantsEnabled" class="checkbox border-solid" />
          Include restaurants
        </label>
        <MultiSelectField
          v-model="includedRestaurants"
          :options="restaurantOptions"
          :labels="restaurantLabels"
          :disabled="!includeRestaurantsEnabled"
        />
      </div>
    </div>
    <div class="flex flex-row flex-nowrap w-full">
      <div class="mx-5 my-4 w-full">
        <label class="form-label mb-2">
          <input type="checkbox" v-model="excludeRestaurantsEnabled" class="checkbox border-solid" />
          Exclude restaurants
        </label>
        <MultiSelectField
          v-model="excludedRestaurants"
          :options="restaurantOptions"
          :labels="restaurantLabels"
          :disabled="!excludeRestaurantsEnabled"
        />
      </div>
    </div>
  </div>
  <div class="flex-1"></div>
  <div>
    {{ errors }}
    {{ filteredRestaurants }} filtered restaurants
    <button @click="onSubmit" class="btn btn-outline w-full">Save preferences</button>
  </div>
</template>
