<template>
  <q-dialog
    v-model="showWishListDialog"
    :maximized="globalStore.$q.screen.lt.md"
    @before-show="getData()"
  >
    <q-card class="dialog-width">
      <q-bar>
        <div>Wish List</div>
        <q-space />
        <q-btn dense flat icon="close" label="Close" v-close-popup />
      </q-bar>
      <q-card-section>
        <q-select
          outlined
          dense
          v-model="wishListName"
          :options="wishListNames"
          class="wish-list-name q-mb-md"
        >
          <template v-slot:prepend>
            <q-icon name="format_list_bulleted" />
          </template>
        </q-select>
        <q-table
          table-class="wish-list"
          :rows="wishListRows"
          :columns="columns"
          :rows-per-page-options="[10, 20, 50, 100]"
          row-key="part_num"
          :filter="filter"
          :grid="globalStore.$q.screen.lt.sm"
          selection="multiple"
          v-model:selected="selected"
          color="primary"
        >
          <!-- Search -->
          <template v-slot:top-left>
            <div class="row">
              <q-input
                dense
                filled
                debounce="300"
                v-model="filter"
                bg-color="white"
                no-error-icon
                hide-bottom-space
                aria-label="Filter"
                placeholder="Filter"
                class="col"
              >
                <template v-slot:prepend>
                  <q-icon name="filter_alt" />
                </template>
              </q-input>
              <q-checkbox
                v-model="hideZeroQty"
                label="Hide 0 Qty"
                class="col q-pr-md"
              />
            </div>
          </template>

          <!-- Export to CSV -->
          <template v-slot:top-right>
            <q-btn
              color="primary"
              icon-right="archive"
              label="Export to CSV"
              no-caps
              @click="exportTable"
            />
          </template>

          <!-- Comments -->
          <template v-slot:body-cell-comments="props">
            <q-td :props="props" class="cursor-pointer">
              {{ props.row.comments }}
              <q-popup-edit
                v-model="props.row.comments"
                v-slot="scope"
                title="Update comments"
                buttons
                persistent
                @update:model-value="
                  wishListStore.editItem(props.row, props.row.qty)
                "
              >
                <q-input
                  type="textarea"
                  v-model="scope.value"
                  dense
                  autofocus
                  autogrow
                />
              </q-popup-edit>
              <q-icon name="edit" />
            </q-td>
          </template>

          <!-- Qty -->
          <template v-slot:body-cell-qty="props">
            <q-td :props="props" class="qty-ordered">
              <q-input
                class="qty-ordered-input shadow-2"
                aria-label="Quantity to add"
                dense
                filled
                bg-color="white"
                no-error-icon
                hide-bottom-space
                type="number"
                min="0"
                :rules="[
                  (val) => globalStore.positiveNumberValidator(val) || '',
                ]"
                v-model="props.row.qty"
                @blur="submitQuantity(props.row)"
                @focus="onFocusInput"
                @keyup.up="enterQuantityAndGoUp(props.row)"
                @keydown.up="ignoreQtyDefaultKeyUpAndDown"
                @keyup.down="enterQuantity(props.row)"
                @keydown.down="ignoreQtyDefaultKeyUpAndDown"
                @keyup.enter="enterQuantity(props.row)"
              >
                <div class="spinner-wrapper hide">
                  <q-inner-loading showing class="spinner-hide">
                    <q-spinner-facebook size="md" />
                  </q-inner-loading>
                </div>
                <template v-slot:append> </template>
              </q-input>
            </q-td>
          </template>

          <!-- Actions -->
          <template v-slot:body-cell-actions="props">
            <q-td :props="props" class="">
              <q-btn
                icon="delete_forever"
                no-caps
                dense
                @click="wishListStore.removeItem(props.row)"
              />
            </q-td>
          </template>

          <!-- Custom card view -->
          <template v-slot:item="props">
            <div
              class="q-pa-xs col-xs-12 col-sm-6 col-md-4 col-lg-3 grid-style-transition"
              :style="props.selected ? 'transform: scale(0.95);' : ''"
            >
              <q-card bordered>
                <q-card-section>
                  <div class="row">
                    <div class="col-3">
                      <template
                        v-for="col in props.cols.filter(
                          (col) =>
                            col.name !== 'description' &&
                            col.name !== 'qty_ordered',
                        )"
                        :key="col.name"
                      >
                        <div>{{ col.label }}</div>
                      </template>
                    </div>
                    <div class="col-6">
                      <template
                        v-for="col in props.cols.filter(
                          (col) =>
                            col.name !== 'description' &&
                            col.name !== 'qty_ordered',
                        )"
                        :key="col.name"
                      >
                        <div class="col-value">{{ col.value }}</div>
                      </template>
                    </div>
                    <div class="col-3 self-center">
                      <q-input
                        class="qty-ordered-input shadow-2"
                        aria-label="Quantity to add"
                        dense
                        filled
                        bg-color="white"
                        no-error-icon
                        hide-bottom-space
                        type="number"
                        min="0"
                        :rules="[
                          (val) =>
                            globalStore.positiveNumberValidator(val) || '',
                        ]"
                        v-model="props.row.qty"
                        @blur="submitQuantity(props.row)"
                        @focus="onFocusInput"
                        @keyup.up="enterQuantityAndGoUp(props.row)"
                        @keydown.up="ignoreQtyDefaultKeyUpAndDown"
                        @keyup.down="enterQuantity(props.row)"
                        @keydown.down="ignoreQtyDefaultKeyUpAndDown"
                        @keyup.enter="enterQuantity(props.row)"
                      >
                        <div class="spinner-wrapper">
                          <q-inner-loading showing class="spinner-hide">
                            <q-spinner-facebook size="md" />
                          </q-inner-loading>
                        </div>
                      </q-input>
                    </div>
                  </div>
                  <div class="q-mt-sm">
                    <template
                      v-for="col in props.cols.filter(
                        (col) => col.name === 'description',
                      )"
                      :key="col.name"
                    >
                      <div>{{ col.value }}</div>
                    </template>
                  </div>
                </q-card-section>
              </q-card>
            </div>
          </template>
        </q-table>
      </q-card-section>
      <q-card-actions class="q-mx-md q-mb-md justify-end items-center">
        <q-btn color="dark" @click="goToUploadTool" class="q-mb-sm" no-caps>
          <q-icon left name="upload_file" />
          <div>Upload file</div>
        </q-btn>
        <q-btn
          v-if="listCount > 0"
          color="dark"
          @click="addSelectedToCart"
          class="q-mb-sm"
          no-caps
        >
          <q-icon left name="add_shopping_cart" />
          <div>Add selected to cart</div>
        </q-btn>
        <q-btn
          v-if="listCount > 0"
          color="red-9"
          @click="clearList"
          class="q-mb-sm"
          no-caps
        >
          <q-icon left name="delete_forever" />
          <div>Delete list</div>
        </q-btn>
        <q-btn
          v-if="listCount > 0"
          color="dark"
          @click="convertCart"
          class="q-mb-sm"
          no-caps
        >
          <q-icon left name="sync" />
          <div>Convert to cart</div>
        </q-btn>
        <q-btn color="dark" class="q-mb-sm" no-caps v-close-popup>
          <q-icon left name="close" />
          <div>Close</div></q-btn
        >
      </q-card-actions>
    </q-card>
  </q-dialog>
</template>

<script setup lang="ts">
import { ref, computed, watch } from 'vue';

const globalStore = window.PiniaStores.useGlobalStore();
const { showWishListDialog } = window.Pinia.storeToRefs(globalStore);
const wishListStore = window.PiniaStores.useWishListStore();
const { wishList, wishListNames, wishListName } =
  window.Pinia.storeToRefs(wishListStore);
const cartStore = window.PiniaStores.useCartStore();

const selected = ref([]);
const filter = ref();
const blurredInputElement = ref();
const focusedInputElement = ref();
const enteredQty = ref(false); // KLUGDE: prevent duplicate call of blur when pressing enter on Qty
const hideZeroQty = ref(false);

const listCount = computed(() => 0 || wishListRows.value?.length);

const wishListHideZeroQty = computed(() =>
  wishList.value?.filter((r) => r.qty_avail !== '0'),
);
const wishListShowZeroQty = computed(() => wishList.value);
const wishListRows = computed(() =>
  hideZeroQty.value ? wishListHideZeroQty.value : wishListShowZeroQty.value,
);

const columns = [
  {
    name: 'part_num',
    required: true,
    label: 'Item #',
    align: 'left',
    field: 'part_num',
    sortable: true,
  },
  {
    name: 'description',
    required: true,
    label: 'Description',
    align: 'left',
    field: 'description',
    sortable: true,
  },
  {
    name: 'qty_avail',
    required: true,
    label: 'Avail',
    align: 'right',
    field: 'qty_avail',
    sortable: true,
  },
  {
    name: 'price',
    required: true,
    label: 'Price',
    align: 'right',
    field: 'price',
    sortable: true,
    format: (val) => `$${val}`,
  },
  {
    name: 'date_changed',
    required: true,
    label: 'Updated',
    align: 'center',
    field: 'date_changed',
    sortable: true,
  },
  {
    name: 'comments',
    label: 'Comments',
    field: 'comments',
    align: 'left',
    sortable: true,
  },
  {
    name: 'qty',
    label: 'Qty',
    field: 'qty',
    align: 'center',
    headerStyle: 'width: 110px',
    headerClasses: 'qty-ordered-th',
    classes: 'qty-ordered-td',
  },
  {
    name: 'actions',
    align: 'center',
  },
];

const getData = async () => {
  await wishListStore.getWishLists();
  await wishListStore.getWishList();
};

const convertCart = () => {
  globalStore.$q
    .dialog({
      title: 'Convert Wish List to Cart',
      message: "What is your new cart's name?",
      prompt: {
        model: wishListName.value,
        type: 'text', // optional
      },
      cancel: true,
      persistent: true,
    })
    .onOk(async (cartName) => {
      const newCartRowId = await cartStore.addCart();
      if (
        newCartRowId &&
        (await cartStore.renameCart(newCartRowId, cartName || 'Wish List Cart'))
      ) {
        // TODO: handle adding item errors
        wishListRows.value.forEach(async (item) => {
          await cartStore.addCartItem(
            item.part_num,
            item.qty,
            item.comments,
            newCartRowId,
          );
        });
        globalStore.notifySuccess(
          'Converted wish list to cart - navigating to new cart now...',
        );
        globalStore.$q
          .dialog({
            message: 'Would you like to navigate to your new cart now?',
            cancel: true,
            persistent: true,
          })
          .onOk(() => {
            globalStore.showLoading('Loading new cart...');
            window.location.href = '/ws/oe/viewcart/';
          });
      } else {
        globalStore.$q.dialog({
          title: 'Failed: Convert wish list to cart',
          message:
            'The operation was not successful, please ensure stable network connection.',
        });
      }
    });
};

const enterQuantity = (row) => {
  submitQuantity(row);
  enteredQty.value = true;
  const inputs = Array.prototype.slice.call(
    document.querySelectorAll('.wish-list .qty-ordered-input input'),
  );
  const currInput = document.activeElement;
  const currInputIndex = inputs.indexOf(currInput);
  if (currInputIndex + 1 === inputs.length) {
    // go to search input
    const input = document.querySelector('.search-bar .search-input input');
    input['focus']?.();
    return;
  }
  const nextinputIndex = (currInputIndex + 1) % inputs.length;
  const input = inputs[nextinputIndex];
  input.focus();
};

const enterQuantityAndGoUp = (row) => {
  submitQuantity(row);
  enteredQty.value = true;
  const inputs = Array.prototype.slice.call(
    document.querySelectorAll('.wish-list .qty-ordered-input input'),
  );
  const currInput = document.activeElement;
  const currInputIndex = inputs.indexOf(currInput);
  const nextinputIndex = (currInputIndex - 1) % inputs.length;

  if (nextinputIndex < 0) {
    // go to search input
    const input = document.querySelector('.search-bar .search-input input');
    input['focus']?.();
    return;
  } else {
    inputs[nextinputIndex]?.focus();
  }
};

const submitQuantity = async (row) => {
  let qty = row.qty;
  let isValid = globalStore.positiveNumberValidator(qty);
  if (qty === undefined || qty.length === 0 || !isValid) return;

  const currentInputSpinnerElement =
    blurredInputElement.value?.nextElementSibling?.firstElementChild;
  currentInputSpinnerElement?.classList?.toggle?.('spinner-hide');
  wishListStore.editItem(row, qty);
  currentInputSpinnerElement?.classList?.toggle?.('spinner-hide');
};

const onFocusInput = () => {
  blurredInputElement.value = focusedInputElement.value;
  focusedInputElement.value = document.activeElement;
};

const ignoreQtyDefaultKeyUpAndDown = ($event) => {
  onFocusInput();
  $event.preventDefault();
};

const clearList = () => {
  globalStore.$q
    .dialog({
      title: 'Confirm',
      message:
        'Are you sure you want to delete this list and all items on this list?',
      cancel: true,
    })
    .onOk(() => {
      wishListStore.removeAllItems();
    });
};

const addSelectedToCart = () => {
  selected.value.forEach(async (item) => {
    await cartStore.addCartItemAndUpdateCartTotals(
      item.part_num,
      item.qty,
      item.comments,
    );
  });
};

const wrapCsvValue = (val, formatFn, row) => {
  let formatted = formatFn !== void 0 ? formatFn(val, row) : val;

  formatted =
    formatted === void 0 || formatted === null ? '' : String(formatted);

  formatted = formatted.split('"').join('""');
  /**
   * Excel accepts \n and \r in strings, but some other CSV parsers do not
   * Uncomment the next two lines to escape new lines
   */
  // .split('\n').join('\\n')
  // .split('\r').join('\\r')

  return `"${formatted}"`;
};

const exportTable = () => {
  // naive encoding to csv format
  const content = [columns.map((col) => wrapCsvValue(col.label))]
    .concat(
      wishListRows.value.map((row) =>
        columns
          .map((col) =>
            wrapCsvValue(
              typeof col.field === 'function'
                ? col.field(row)
                : row[col.field === void 0 ? col.name : col.field],
              col.format,
              row,
            ),
          )
          .join(','),
      ),
    )
    .join('\r\n');

  const status = globalStore.exportFile(
    'My-Wish-List.csv',
    content,
    'text/csv',
  );

  if (status !== true) {
    globalStore.$q.notify({
      message: 'Browser denied file download...',
      color: 'negative',
      icon: 'warning',
    });
  }
};

const goToUploadTool = () => (window.location.href = '/ws/ordering/ordUpload/');

watch(
  wishListName,
  () => showWishListDialog.value && wishListStore.getWishList(),
);
</script>

<style scoped>
.dialog-width {
  width: 95vw;
  min-width: 95vw;
  min-height: 95vh;
  height: max-content;
}

.search-lookup {
  border: gray solid 1px;
  border-radius: 4px;
  padding: 0;
  min-width: 50px;
}
</style>

<style>
.wish-list {
  width: 100%;
}

.wish-list .q-table thead,
.wish-list .q-table th {
  font-size: 1.5rem;
  background-color: #313131;
  color: white;
}

.wish-list .q-table tbody td {
  font-size: 1em;
  color: black;
}

.wish-list .q-table tbody tr:nth-child(odd) {
  background-color: #eee;
}

.wish-list .qty-ordered-input {
  border: gray solid 1px;
  border-radius: 4px;
  padding: 0;
  min-width: 50px;
}

.wish-list .qty-ordered-input input {
  text-align: center;
}

.wish-list .qty-ordered-input:focus-within {
  background-color: white !important;
  outline: 2px #ee8900 solid;
  border: none;
}

.wish-list .search-wish-list:focus-within {
  outline: 2px #ee8900 solid;
  border: 1px #ee8900 solid;
}

.wish-list input[type='text']:focus {
  background-color: white !important;
}

.wish-list .q-table tbody tr:hover {
  background-color: rgb(239, 238, 201);
}

.wish-list .q-field--dense .q-field__control,
.wish-list .q-field--dense .q-field__marginal {
  height: 30px;
}

.wish-list th .q-checkbox__inner {
  color: white;
}
</style>
