<script lang="ts" setup>
import { storeToRefs } from 'pinia';
import { onMounted, nextTick, ref, watch, toRaw } from 'vue';
import { precisionRound } from 'src/utils/arithmetic';
import { useI18n } from 'vue-i18n';
import ThaiBahtText from 'thai-baht-text';

// NOTE: Import stores
import { dialogWarningClose, formatNumberDecimal } from 'stores/utils';
import { useConfigStore } from 'stores/config';
import useBranchStore from 'stores/branch';
import { baseUrl } from 'stores/utils';
import useCustomerStore from 'stores/customer';
import { useQuotationStore } from 'src/stores/quotations';

// NOTE  Import Types
import { CustomerBranch } from 'stores/customer/types';
import { BankBook, Branch } from 'stores/branch/types';
import {
  QuotationPayload,
  Details,
  QuotationFull,
  ProductRelation,
} from 'src/stores/quotations/types';

// NOTE: Import Components
import ViewPDF from './ViewPdf.vue';
import ViewHeader from './ViewHeader.vue';
import ViewFooter from './ViewFooter.vue';
import BankComponents from './BankComponents.vue';
import PrintButton from 'src/components/button/PrintButton.vue';
import { CancelButton } from 'components/button';
import { convertTemplate } from 'src/utils/string-template';

const configStore = useConfigStore();
const branchStore = useBranchStore();
const customerStore = useCustomerStore();
const quotationStore = useQuotationStore();
const { t } = useI18n();
const { data: config } = storeToRefs(configStore);

type Product = {
  id: string;
  code: string;
  detail: string;
  amount: number;
  pricePerUnit: number;
  discount: number;
  vat: number;
  value: number;
  calcVat: boolean;
  product: ProductRelation;
};

type SummaryPrice = {
  totalPrice: number;
  totalDiscount: number;
  vat: number;
  vatExcluded: number;
  finalPrice: number;
};

const customer = ref<CustomerBranch>();
const branch = ref<Branch>();
const productList = ref<Product[]>([]);
const bankList = ref<BankBook[]>([]);

const agentPrice = ref(false);

const elements = ref<HTMLElement[]>([]);
const chunks = ref<Product[][]>([[]]);
const attachmentList = ref<
  {
    url: string;
    isImage?: boolean;
    isPDF?: boolean;
  }[]
>([]);
const data = ref<QuotationFull & { remark?: string }>();

const summaryPrice = ref<SummaryPrice>({
  totalPrice: 0,
  totalDiscount: 0,
  vat: 0,
  vatExcluded: 0,
  finalPrice: 0,
});

async function fetchQuotationById(id: string, codeInvoice: string) {
  const res = await quotationStore.getQuotation(id);
  if (res) {
    const installmentNo = res.paySplit.find(
      (v) => codeInvoice === v.invoice?.code,
    )?.no;

    data.value = {
      ...res,
      productServiceList: !!installmentNo
        ? res.productServiceList.filter(
            (v) => installmentNo === v.installmentNo,
          )
        : res.productServiceList,
    };
  }
}

async function getAttachment(quotationId: string) {
  const attachment = await quotationStore.listAttachment({
    parentId: quotationId,
  });

  if (attachment) {
    attachmentList.value = await Promise.all(
      attachment.map(async (v) => {
        const url = await quotationStore.getAttachment({
          parentId: quotationId,
          name: v,
        });
        const ft = v.substring(v.lastIndexOf('.') + 1);

        return {
          url,
          isImage: ['png', 'jpg', 'jpeg'].includes(ft),
          isPDF: ft === 'pdf',
        };
      }),
    );
  }
}

async function assignData() {
  for (let i = 0; i < productList.value.length; i++) {
    let el = elements.value.at(-1);

    if (!el) return;

    if (getHeight(el) < 500) {
      chunks.value.at(-1)?.push(productList.value[i]);
    } else {
      chunks.value.push([]);
      i--;
    }

    await nextTick();
  }
}

function getHeight(el: HTMLElement) {
  const shadow = document.createElement('div');

  shadow.style.opacity = '0';
  shadow.style.position = 'absolute';
  shadow.style.top = '-999999px';
  shadow.style.left = '-999999px';
  shadow.style.pointerEvents = 'none';

  document.body.appendChild(shadow);

  shadow.appendChild(el.cloneNode(true));

  const height = shadow.offsetHeight;

  document.body.removeChild(shadow);

  return height;
}

const details = ref<Details>();
enum View {
  Quotation,
  Invoice,
  Payment,
  Receipt,
}
const view = ref<View>(View.Quotation);

onMounted(async () => {
  await configStore.getConfig();

  const currentDocumentType = new URL(window.location.href).searchParams.get(
    'type',
  );

  if (currentDocumentType === 'invoice') view.value = View.Invoice;
  if (currentDocumentType === 'payment') view.value = View.Payment;
  if (currentDocumentType === 'receipt') view.value = View.Receipt;

  let str =
    localStorage.getItem('quotation-preview') ||
    sessionStorage.getItem('quotation-preview');

  if (!str) return;

  const obj: QuotationPayload = JSON.parse(str);

  if (obj) sessionStorage.setItem('quotation-preview', JSON.stringify(obj));

  delete localStorage['quotation-preview'];

  const parsed = JSON.parse(sessionStorage.getItem('quotation-preview') || '');

  data.value = 'data' in parsed ? parsed.data : undefined;

  if (data.value) {
    if (!!data.value.id) {
      await getAttachment(data.value.id);
      if (parsed.data.fetch)
        await fetchQuotationById(data.value.id, parsed.data.codeInvoice);
    }

    const resCustomerBranch = await customerStore.getBranchById(
      data.value?.customerBranchId,
    );

    if (resCustomerBranch) {
      customer.value = resCustomerBranch;
    }

    agentPrice.value = data.value.agentPrice || parsed?.meta?.agentPrice;

    const currentCode =
      view.value === View.Invoice
        ? parsed.data.codeInvoice
        : view.value === View.Payment
          ? parsed.data.codePayment
          : (parsed?.meta?.source?.code ?? data.value?.code);

    details.value = {
      code: currentCode,
      createdAt:
        parsed?.meta?.source?.createdAt ??
        new Date(data.value?.createdAt || ''),
      createdBy:
        `${parsed?.meta?.source?.createdBy?.firstName ?? ''} ${parsed?.meta?.source?.createdBy?.telephoneNo ?? ''}`.trim() ||
        `${data.value?.createdBy?.firstName ?? ''} ${data.value?.createdBy?.telephoneNo ?? ''}`.trim(),
      payCondition:
        parsed?.meta?.source?.payCondition ?? data.value?.payCondition,
      contactName: parsed?.meta?.source?.contactName ?? data.value?.contactName,
      contactTel: parsed?.meta?.source?.contactTel ?? data.value?.contactTel,
      workName: parsed?.meta?.source?.workName ?? data.value?.workName,
      dueDate:
        parsed?.meta?.source?.dueDate ?? new Date(data.value?.dueDate || ''),
      worker:
        parsed?.meta?.selectedWorker ??
        data.value?.worker.map((v) => v.employee),
    };

    const resBranch = await branchStore.fetchById(
      data.value?.registeredBranchId ?? data.value?.registeredBranchId,
    );

    if (resBranch) {
      branch.value = resBranch;

      bankList.value = resBranch.bank.map((v) => ({
        ...v,
        bankUrl: `${baseUrl}/branch/${resBranch.id}/bank-qr/${v.id}?ts=${Date.now()}`,
      }));
    }

    productList.value =
      (data?.value?.productServiceList ?? data.value?.productServiceList).map(
        (v) => {
          return {
            id: v.product.id,
            code: v.product.code,
            detail: v.product.name,
            amount: v.amount || 0,
            pricePerUnit: v.pricePerUnit || 0,
            discount: v.discount || 0,
            vat: v.vat || 0,
            value: 0,
            calcVat: v.vat > 0,
            product: v.product,
          };
        },
      ) || [];
  }

  summaryPrice.value = (
    (data?.value?.productServiceList ?? data.value?.productServiceList) ||
    []
  ).reduce(
    (a, c) => {
      const calcVat = c.vat > 0;
      const vatFactor = calcVat ? (config.value?.vat ?? 0.07) : 0;
      const pricePerUnit =
        precisionRound(c.pricePerUnit * (1 + vatFactor)) / (1 + vatFactor);
      const price =
        (pricePerUnit * c.amount * (1 + vatFactor) - c.discount) /
        (1 + vatFactor);

      a.totalPrice = precisionRound(a.totalPrice + price + c.discount);
      a.totalDiscount = precisionRound(a.totalDiscount + Number(c.discount));
      a.vat = calcVat ? precisionRound(a.vat + c.vat) : a.vat;
      a.vatExcluded = calcVat
        ? a.vatExcluded
        : precisionRound(a.vatExcluded + price);
      a.finalPrice = precisionRound(
        a.totalPrice -
          a.totalDiscount +
          a.vat -
          Number(data.value?.discount || 0),
      );
      return a;
    },
    {
      totalPrice: 0,
      totalDiscount: 0,
      vat: 0,
      vatExcluded: 0,
      finalPrice: 0,
    },
  );

  assignData();
});

function calcPrice(c: Product) {
  const originalPrice = c.pricePerUnit;
  const finalPricePerUnit = precisionRound(
    originalPrice +
      (c.calcVat ? originalPrice * (config.value?.vat || 0.07) : 0),
  );
  const price = finalPricePerUnit * c.amount - c.discount;
  return precisionRound(price);
}

async function closeTab() {
  dialogWarningClose(t, {
    message: t('dialog.message.close'),
    action: () => {
      window.close();
    },
    cancel: () => {},
  });
}

function closeAble() {
  return window.opener !== null;
}

watch(elements, () => {});

function print() {
  window.print();
}
</script>

<template>
  <div class="toolbar">
    <PrintButton solid @click="print" />
    <CancelButton
      outlined
      id="btn-close"
      @click="closeTab()"
      :label="$t('dialog.action.close')"
      v-if="closeAble()"
    />
  </div>

  <div
    class="row justify-between container color-quotation"
    :class="{
      'color-quotation': view === View.Quotation,
      'color-invoice': view === View.Invoice,
      'color-receipt': view === View.Receipt,
    }"
  >
    <section class="content" v-for="chunk in chunks">
      <ViewHeader
        v-if="!!branch && !!customer && !!details"
        :branch="branch"
        :customer="customer"
        :details="details"
        :view="view"
      />

      <span
        class="q-mb-sm q-mt-md"
        style="
          font-weight: 800;
          font-size: 16px;
          color: var(--main);
          display: block;
          border-bottom: 2px solid var(--main);
        "
      >
        {{ $t('preview.productList') }}
      </span>

      <table ref="elements" class="q-mb-sm" cellpadding="0" style="width: 100%">
        <tbody class="color-tr">
          <tr>
            <th>{{ $t('preview.rank') }}</th>
            <th>{{ $t('preview.productCode') }}</th>
            <th>{{ $t('general.detail') }}</th>
            <th>{{ $t('general.amount') }}</th>
            <th>{{ $t('preview.pricePerUnit') }}</th>
            <th>{{ $t('preview.discount') }}</th>
            <th>{{ $t('preview.vat') }}</th>
            <th>{{ $t('preview.value') }}</th>
          </tr>
          <tr v-for="(v, i) in chunk">
            <td class="text-center">{{ i + 1 }}</td>
            <td>{{ v.code }}</td>
            <td>{{ v.detail }}</td>
            <td style="text-align: right">{{ v.amount }}</td>
            <td style="text-align: right">
              {{ formatNumberDecimal(v.pricePerUnit, 2) }}
            </td>
            <td style="text-align: right">
              {{ formatNumberDecimal(v.discount, 2) }} ฿
            </td>
            <td style="text-align: right">
              {{ Math.round((v.vat > 0 ? config?.vat || 0.07 : 0) * 100) }}%
            </td>
            <td style="text-align: right">
              {{ formatNumberDecimal(calcPrice(v), 2) }}
            </td>
          </tr>
        </tbody>
      </table>

      <table
        style="width: 40%; margin-left: auto"
        class="q-mb-md"
        cellpadding="0"
      >
        <tbody class="color-tr">
          <tr>
            <td>{{ $t('general.total') }}</td>
            <td class="text-right">
              {{ formatNumberDecimal(summaryPrice.totalPrice, 2) }}
              ฿
            </td>
          </tr>

          <tr>
            <td>{{ $t('general.discount') }}</td>
            <td class="text-right">
              {{ formatNumberDecimal(summaryPrice.totalDiscount, 2) || 0 }} ฿
            </td>
          </tr>
          <tr>
            <td>{{ $t('general.totalAfterDiscount') }}</td>
            <td class="text-right">
              {{
                formatNumberDecimal(
                  summaryPrice.totalPrice - summaryPrice.totalDiscount,
                  2,
                )
              }}
              ฿
            </td>
          </tr>

          <tr>
            <td>{{ $t('general.totalVatExcluded') }}</td>
            <td class="text-right">
              {{ formatNumberDecimal(summaryPrice.vatExcluded, 2) || 0 }}
              ฿
            </td>
          </tr>
          <tr>
            <td>{{ $t('general.vat', { msg: '7%' }) }}</td>
            <td class="text-right">
              {{ formatNumberDecimal(summaryPrice.vat, 2) }} ฿
            </td>
          </tr>
          <tr>
            <td>{{ $t('general.totalVatIncluded') }}</td>
            <td class="text-right">
              {{
                formatNumberDecimal(
                  summaryPrice.totalPrice -
                    summaryPrice.totalDiscount -
                    summaryPrice.vatExcluded,
                  2,
                )
              }}
              ฿
            </td>
          </tr>

          <tr>
            <td>{{ $t('general.discountAfterVat') }}</td>
            <td class="text-right">
              {{ formatNumberDecimal(data?.discount || 0, 2) }}
              ฿
            </td>
          </tr>
        </tbody>
      </table>

      <div class="row justify-between q-mb-md" style="width: 100%">
        <div
          class="column set-width bg-color full-height"
          style="padding: 12px"
        >
          ({{ ThaiBahtText(summaryPrice.finalPrice) || 'ศูนย์บาทถ้วน' }})
        </div>
        <div
          class="row text-right border-5 items-center"
          style="width: 40%; background: var(--main); padding: 8px"
        >
          <span style="color: white; font-weight: 600">
            {{ $t('quotation.totalPrice') }}
          </span>
          <span
            class="border-5"
            style="
              width: 70%;
              margin-left: auto;
              background: white;
              padding: 4px;
            "
          >
            {{
              formatNumberDecimal(Math.max(summaryPrice.finalPrice, 0), 2) || 0
            }}
            ฿
          </span>
        </div>
      </div>
    </section>

    <section class="content">
      <ViewHeader
        v-if="!!branch && !!customer && !!details"
        :branch="branch"
        :customer="customer"
        :details="details"
        :view="view"
      />

      <span
        class="q-mb-sm q-mt-md"
        style="
          font-weight: 800;
          font-size: 16px;
          color: var(--main);
          display: block;
          border-bottom: 2px solid var(--main);
        "
      >
        {{ $t('general.remark') }}
      </span>

      <div
        class="border-5 surface-0 detail-note q-mb-md"
        style="width: 100%; padding: 8px 16px; white-space: pre-wrap"
      >
        <div
          v-html="
            convertTemplate(data?.remark || '', {
              'quotation-payment': {
                paymentType: data?.payCondition || 'Full',
                amount: summaryPrice.finalPrice,
                installments: data?.paySplit,
              },
              'quotation-labor': {
                name:
                  details?.worker.map(
                    (v, i) =>
                      `${i + 1}. ` +
                      `${v.employeePassport.length !== 0 ? v.employeePassport[0].number + '_' : ''}${v.namePrefix}. ${v.firstNameEN ? `${v.firstNameEN} ${v.lastNameEN}` : `${v.firstName} ${v.lastName}`}  `.toUpperCase(),
                  ) || [],
              },
            }) || '-'
          "
        ></div>
      </div>
    </section>

    <section class="content">
      <ViewHeader
        v-if="!!branch && !!customer && !!details"
        :branch="branch"
        :customer="customer"
        :details="details"
        :view="view"
      />

      <span
        class="q-mb-sm"
        style="
          font-weight: 800;
          font-size: 16px;
          color: var(--main);
          display: block;
          border-bottom: 2px solid var(--main);
        "
      >
        {{ $t('quotation.paymentChannels') }}
      </span>
      <article style="height: 5.8in">
        <BankComponents
          v-for="(bank, index) in bankList"
          :index="index"
          :bank-book="bank"
          :key="bank.id"
        />
      </article>

      <ViewFooter
        :data="{
          name: '',
          company: branch?.name || '',
          buyer: '',
          buyDate: '',
          approveDate: '',
          approver: '',
        }"
      />
    </section>

    <section
      v-for="item in attachmentList.filter((v) => v.isImage)"
      class="content"
    >
      <q-img :src="item.url" />
    </section>

    <ViewPDF
      v-for="item in attachmentList.filter((v) => v.isPDF)"
      :url="item.url"
    />
  </div>
</template>

<style scoped>
.color-quotation {
  --main: var(--orange-6);
  --main-hsl: var(--orange-6-hsl);
}

.color-invoice {
  --main: var(--purple-9);
  --main-hsl: var(--purple-9-hsl);
}

.color-receipt {
  --main: var(--green-6);
  --main-hsl: var(--green-6-hsl);
}

.toolbar {
  width: 100%;
  position: sticky;
  top: 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1rem;
  padding: 1rem;
  background: white;
  border-bottom: 1px solid var(--gray-3);
  z-index: 99999;
}

table {
  border-collapse: collapse;
}

th {
  background: var(--main);
  color: white;

  padding: 4px;
}
td {
  padding: 4px 8px;
}

.border-5 {
  border-radius: 5px;
}
.set-width {
  width: 50%;
}

.bg-color {
  background-color: hsla(var(--main-hsl) / 0.1);
}

.color-tr > tr:nth-child(odd) {
  background-color: hsla(var(--main-hsl) / 0.1);
}

.container {
  padding: 1rem;
  display: flex;
  gap: 1rem;
  margin-inline: auto;
  background: var(--gray-3);
  width: calc(8.3in + 1rem);
}

.container :deep(*) {
  font-size: 95%;
}

.content {
  width: 100%;
  padding: 0.5in;
  align-items: center;
  background: white;
  page-break-after: always;
  break-after: page;
  height: 11.7in;
  max-height: 11.7in;
}

.position-bottom {
  margin-top: auto;
}

.detail-note {
  display: flex;
  flex-direction: column;
  gap: 8px;
  & > * {
    display: flex;
    flex-direction: column;
  }
}

hr {
  border-style: solid;
  border-color: var(--main);
}

@media print {
  .toolbar {
    display: none;
  }

  .container {
    padding: 0;
    gap: 0;
    width: 100%;
    background: white;
  }

  .content {
    padding: 0;
    height: unset;
  }
}
</style>
