<script setup lang="ts">
import { useI18n } from 'vue-i18n';
import { QTableColumn, QTableSlots } from 'quasar';
import { computed, reactive, ref, watch } from 'vue';
import { calculateAge, dateFormatJS } from 'src/utils/datetime';

import useOptionStore from 'src/stores/options';
import useEmployeeStore from 'src/stores/employee';
import { useQuotationStore } from 'src/stores/quotations';
import { Employee } from 'src/stores/employee/types';

import {
  CancelButton,
  BackButton,
  NextButton,
  ImportButton,
  AddButton,
} from 'components/button';
import DialogContainer from 'components/dialog/DialogContainer.vue';
import DialogHeader from 'components/dialog/DialogHeader.vue';
import ImportWorker from './ImportWorker.vue';
import PersonCard from 'src/components/shared/PersonCard.vue';
import { QuotationFull } from 'src/stores/quotations/types';
import { Lang } from 'src/utils/ui';
import NoData from 'src/components/NoData.vue';

const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;

const { locale } = useI18n();
const columns = [
  {
    name: '#check',
    align: 'left',
    label: '',
    field: (_) => '#check',
  },
  {
    name: 'order',
    align: 'center',
    label: 'general.order',
    field: (e: Employee & { _index: number }) => e._index + 1,
  },
  {
    name: 'foreignRefNo',
    align: 'center',
    label: 'quotation.foreignRefNo',
    field: (v: Employee) =>
      v.employeePassport !== undefined
        ? v.employeePassport[0]?.number || '-'
        : '-',
  },
  {
    name: 'employeeName',
    align: 'left',
    label: 'quotation.employeeName',
    field: (v: Employee) =>
      locale.value === Lang.English
        ? `${v.firstNameEN} ${v.lastNameEN}`
        : `${v.firstName} ${v.lastName}`,
  },
  {
    name: 'birthDate',
    align: 'left',
    label: 'general.birthDate',
    field: (v: Employee) => dateFormatJS({ date: v.dateOfBirth }),
  },
  {
    name: 'age',
    align: 'left',
    label: 'general.age',
    field: (v: Employee) => calculateAge(v.dateOfBirth),
  },
  {
    name: 'nationality',
    align: 'left',
    label: 'general.nationality',
    field: (v: Employee) => optionStore.mapOption(v.nationality),
  },
  {
    name: 'documentExpireDate',
    align: 'left',
    label: 'quotation.documentExpireDate',
    field: (v: Employee) =>
      v.employeePassport !== undefined &&
      v.employeePassport[0]?.expireDate !== undefined
        ? dateFormatJS({ date: v.employeePassport[0]?.expireDate })
        : '-',
  },
] satisfies QTableColumn[];

const props = defineProps<{
  customerBranchId?: string;
  disabledWorkerId?: string[];
  productServiceList: QuotationFull['productServiceList'];
  quotationId: string;
}>();

const emits = defineEmits<{
  (e: 'success'): void;
}>();

const optionStore = useOptionStore();
const employeeStore = useEmployeeStore();
const quotationStore = useQuotationStore();

const open = defineModel<boolean>('open', { default: false });
const workerSelected = ref<Employee[]>([]);
const workerList = ref<Employee[]>([]);
const importWorkerCriteria = ref<{
  passport: string[] | null;
  visa: string[] | null;
}>({
  passport: [],
  visa: [],
});

type ProductServiceId = string;
const productWorkerMap = ref<Record<ProductServiceId, Employee[]>>({});

const state = reactive({
  importWorker: false,
  step: 1,
  search: '',
});

const submitDisabled = computed(
  () =>
    Object.entries(productWorkerMap.value).some(
      ([productServiceId, employee]) => {
        const productService = props.productServiceList.find(
          (item) => item.id === productServiceId,
        );

        if (!productService) return;

        const limit = productService.amount;
        const current = productService.worker.length + employee.length;

        return current > limit;
      },
    ) ||
    Object.values(productWorkerMap.value).every(
      (employee) => employee.length === 0,
    ),
);

function next() {
  if (state.step >= 2) return addWorker();
  state.step++;
}

function prev() {
  if (state.step <= 0) return;
  state.step--;
}

function clean() {
  workerList.value = [];
  workerSelected.value = [];
  open.value = false;
}

function selectedIndex(item: Employee) {
  return workerSelected.value.findIndex((v) => v.id === item.id);
}

function toggleSelect(item: Employee) {
  if (props.disabledWorkerId?.some((id) => id === item.id)) return;

  const index = selectedIndex(item);

  if (index === -1) {
    workerSelected.value.push(item);
    productWorkerMap.value = props.productServiceList.reduce<
      typeof productWorkerMap.value
    >((acc, curr) => {
      acc[curr.id] = (productWorkerMap.value[curr.id] || []).concat(item);
      return acc;
    }, {});
  } else {
    workerSelected.value.splice(index, 1);
    productWorkerMap.value = props.productServiceList.reduce<
      typeof productWorkerMap.value
    >((acc, curr) => {
      acc[curr.id] =
        productWorkerMap.value[curr.id]?.filter((v) => v.id !== item.id) || [];
      return acc;
    }, {});
  }
}

function toSubmitData(data: typeof productWorkerMap.value) {
  type EmployeeId = string;
  type ProductServiceId = string;
  const ret: Record<EmployeeId, ProductServiceId[]> = {};
  for (const [productServiceId, employee] of Object.entries(data)) {
    employee.forEach((emp) => {
      if (ret[emp.id]) {
        ret[emp.id].push(productServiceId);
      } else {
        ret[emp.id] = [productServiceId];
      }
    });
  }
  return Object.entries(ret).map(([workerId, productServiceId]) => ({
    workerId,
    productServiceId,
  }));
}

function getProductImageUrl(
  item: QuotationFull['productServiceList'][number]['product'],
) {
  return `${API_BASE_URL}/product/${item.id}/image/${item.selectedImage}`;
}

function getEmployeeImageUrl(item: Employee) {
  if (item.selectedImage) {
    return `${API_BASE_URL}/employee/${item.id}/image/${item.selectedImage}`;
  }
  // NOTE: static image
  return '/images/employee-avatar.png';
}

async function getWorkerList() {
  const ret = await employeeStore.fetchList({
    pageSize: 100,
    query: state.search,
    passport: true,
    customerBranchId: props.customerBranchId,
    activeOnly: true,
  });

  if (!ret) return false;

  workerList.value = ret.result;
}

async function addWorker() {
  await quotationStore.addQuotationWorker(
    props.quotationId,
    toSubmitData(productWorkerMap.value),
  );
  emits('success');
}

async function getWorkerFromCriteria(
  payload: typeof importWorkerCriteria.value,
) {
  const ret = await employeeStore.fetchList({
    payload: {
      passport: payload.passport || undefined,
    },
    pageSize: 99999, // must include all possible worker
    page: 1,
    passport: true,
    customerBranchId: props.customerBranchId,
  });

  if (!ret) return false; // error, do not close dialog

  workerSelected.value = ret.result.filter(
    (lhs) => !props.disabledWorkerId?.find((rhs) => lhs.id === rhs),
  );
  workerSelected.value.forEach((item) => {
    productWorkerMap.value = props.productServiceList.reduce<
      typeof productWorkerMap.value
    >((acc, curr) => {
      acc[curr.id] = (productWorkerMap.value[curr.id] || []).concat(item);
      return acc;
    }, {});
  });

  if (workerSelected.value.length > 0) state.step = 2;

  return true;
}

watch(() => state.search, getWorkerList);
</script>

<template>
  <ImportWorker
    v-model:open="state.importWorker"
    v-model:data="importWorkerCriteria"
    :import-worker="getWorkerFromCriteria"
  />
  <DialogContainer v-model="open" @open="getWorkerList" @close="clean">
    <template #header>
      <DialogHeader :title="$t('quotation.addWorker')">
        <template #title-before>
          <span class="q-mr-auto"></span>
        </template>
        <template #title-after>
          <ImportButton
            v-if="state.step === 1"
            icon-only
            class="q-ml-auto q-mr-xs"
            @click="state.importWorker = true"
            :label="$t('quotation.importWorker')"
          />
        </template>
      </DialogHeader>
    </template>
    <div class="col scroll">
      <q-tab-panels
        class="surface-0 rounded full-height"
        v-model="state.step"
        animated
      >
        <q-tab-panel class="q-pa-none" :name="1">
          <div class="column q-pa-md full-height">
            <section class="row justify-end q-mb-md">
              <q-input
                for="input-search"
                outlined
                dense
                :label="$t('general.search')"
                :bg-color="$q.dark.isActive ? 'dark' : 'white'"
                v-model="state.search"
                debounce="500"
              >
                <template #prepend>
                  <q-icon name="mdi-magnify" />
                </template>
              </q-input>
            </section>
            <!-- wrapper -->
            <div class="col scroll">
              <section
                :class="{ ['items-center']: workerList.length === 0 }"
                class="row q-col-gutter-md"
              >
                <div
                  style="display: inline-block; margin-inline: auto"
                  v-if="workerList.length === 0"
                >
                  <NoData :not-found="!!state.search" />
                </div>
                <div
                  :key="emp.id"
                  v-for="(emp, index) in workerList.map((data) => ({
                    ...data,
                    _selectedIndex: selectedIndex(data),
                  }))"
                  class="col-2"
                >
                  <button
                    class="selectable-item full-width"
                    :class="{
                      ['selectable-item__selected']: emp._selectedIndex !== -1,
                      ['selectable-item__disabled']: disabledWorkerId?.some(
                        (id) => id === emp.id,
                      ),
                    }"
                    @click="toggleSelect(emp)"
                  >
                    <span class="selectable-item__pos">
                      {{ emp._selectedIndex + 1 }}
                    </span>
                    <PersonCard
                      no-action
                      class="full-width"
                      :prefix-id="'employee-' + index"
                      :data="{
                        name:
                          locale === Lang.English
                            ? `${emp.firstNameEN} ${emp.lastNameEN}`
                            : `${emp.firstName} ${emp.lastName}`,
                        code: emp.employeePassport?.at(0)?.number || '-',
                        female: emp.gender === 'female',
                        male: emp.gender === 'male',
                        img: getEmployeeImageUrl(emp),
                        fallbackImg: '/images/employee-avatar.png',
                        detail: [
                          {
                            icon: 'mdi-passport',
                            value: optionStore.mapOption(emp.nationality),
                          },
                          {
                            icon: 'mdi-clock-outline',
                            value: calculateAge(emp.dateOfBirth),
                          },
                        ],
                      }"
                    />
                  </button>
                </div>
              </section>
            </div>
          </div>
        </q-tab-panel>
        <q-tab-panel class="q-pa-none" :name="2">
          <div class="column no-wrap full-height q-pa-md">
            <section class="q-mb-md">
              <BackButton icon-only @click="prev" />
            </section>
            <section class="full-height scroll col">
              <div class="rounded column" style="gap: var(--size-4)">
                <q-expansion-item
                  dense
                  default-opened
                  class="overflow-hidden rounded"
                  switch-toggle-side
                  expand-icon="mdi-chevron-down-circle"
                  header-class="q-py-sm text-medium text-body items-center surface-1"
                  v-for="{ id, amount, worker, product } in productServiceList"
                >
                  <template #header>
                    <q-avatar class="q-mr-md" size="md">
                      <q-img
                        class="text-center"
                        :ratio="1"
                        :src="getProductImageUrl(product)"
                      >
                        <template #error>
                          <q-icon
                            class="full-width full-height"
                            name="mdi-shopping-outline"
                            :style="`color: var(--teal-10); background: hsla(var(--teal-${$q.dark.isActive ? '8' : '10'}-hsl)/0.15)`"
                          />
                        </template>
                      </q-img>
                    </q-avatar>
                    <span>
                      {{ product.name }}
                      <div class="app-text-muted text-caption">
                        {{ product.code }}
                      </div>
                    </span>
                    <span
                      class="q-ml-auto"
                      :class="{
                        ['app-text-negative']:
                          worker.length + (productWorkerMap[id]?.length || 0) >
                          amount,
                        ['app-text-positive']:
                          worker.length +
                            (productWorkerMap[id]?.length || 0) ===
                          amount,
                        ['app-text-warning']:
                          worker.length + (productWorkerMap[id]?.length || 0) <
                          amount,
                      }"
                    >
                      {{
                        worker.length + (productWorkerMap[id]?.length || 0)
                      }}/{{ amount }}
                    </span>
                  </template>

                  <div class="q-pa-md surface-1">
                    <q-table
                      v-model:selected="productWorkerMap[id]"
                      :rows-per-page-options="[0]"
                      :rows="
                        workerSelected.map((data, i) => ({
                          ...data,
                          _index: i,
                        }))
                      "
                      :columns
                      hide-bottom
                      bordered
                      flat
                      hide-pagination
                      selection="multiple"
                      card-container-class="q-col-gutter-sm"
                      class="full-width"
                    >
                      <template v-slot:header="props">
                        <q-tr
                          style="background-color: hsla(var(--info-bg) / 0.07)"
                          :props="props"
                        >
                          <q-th
                            v-for="col in columns"
                            :key="col.name"
                            :props="props"
                          >
                            <template v-if="!col.name.startsWith('#')">
                              {{ $t(col.label) }}
                            </template>
                            <template v-if="col.name === '#check'">
                              <q-checkbox v-model="props.selected" size="sm" />
                            </template>
                          </q-th>
                        </q-tr>
                      </template>

                      <template
                        v-slot:body="props: {
                          row: Employee & { _index: number };
                        } & Omit<Parameters<QTableSlots['body']>[0], 'row'>"
                      >
                        <q-tr
                          :class="{ dark: $q.dark.isActive }"
                          class="text-center"
                        >
                          <q-td v-for="col in columns" :align="col.align">
                            <!-- NOTE: custom column will starts with # -->
                            <template v-if="!col.name.startsWith('#')">
                              <q-avatar
                                v-if="col.name === 'employeeName'"
                                class="q-mr-sm"
                                size="md"
                              >
                                <q-img
                                  :src="getEmployeeImageUrl(props.row)"
                                  :ratio="1"
                                  class="text-center"
                                />
                              </q-avatar>
                              <span>
                                {{
                                  typeof col.field === 'string'
                                    ? props.row[col.field as keyof Employee]
                                    : col.field(props.row)
                                }}
                              </span>
                            </template>
                            <template v-if="col.name === '#check'">
                              <q-checkbox v-model="props.selected" size="sm" />
                            </template>
                          </q-td>
                        </q-tr>
                      </template>
                    </q-table>
                  </div>
                </q-expansion-item>
              </div>
            </section>
          </div>
          <!-- TODO: Select product for each worker -->
        </q-tab-panel>
      </q-tab-panels>
    </div>
    <template #footer>
      <CancelButton
        class="q-ml-auto"
        outlined
        @click="clean"
        v-if="state.step === 1"
      />
      <BackButton
        class="q-ml-auto"
        outlined
        @click="prev"
        v-if="state.step === 2"
      />
      <NextButton
        class="q-ml-sm"
        solid
        @click="next"
        :amount="workerSelected.length"
        v-if="state.step === 1"
        :disabled="workerSelected.length <= 0"
      />
      <AddButton
        class="q-ml-sm"
        solid
        @click="next"
        v-if="state.step === 2"
        :disabled="submitDisabled"
      />
    </template>
  </DialogContainer>
</template>

<style scoped>
.selectable-item {
  padding: 0;
  appearance: none;
  border: none;
  background: transparent;
  position: relative;
  color: inherit;

  & > .selectable-item__pos {
    display: none;
  }
}

.selectable-item__selected {
  & > :deep(*) {
    border: 1px solid var(--_color, var(--brand-1)) !important;
  }

  & > .selectable-item__pos {
    display: block;
    position: absolute;
    margin: var(--size-2);
    right: 0;
    top: 0;
    border-radius: 50%;
    width: 20px;
    height: 20px;
    color: var(--surface-1);
    background: var(--brand-1);
    color: currentColor;
  }
}

.selectable-item__disabled {
  filter: grayscale(1);
  opacity: 0.5;

  & :deep(*) {
    cursor: not-allowed;
  }
}
</style>
