<script setup lang="ts">
import { useQuasar } from 'quasar';
import { ref, onMounted, reactive, computed } from 'vue';
import { api } from 'src/boot/axios';
import { useRoute, useRouter } from 'vue-router';
import { dateFormatJS, calculateAge } from 'src/utils/datetime';
import { initLang, initTheme, Lang } from 'src/utils/ui';
import { useQuotationStore } from 'src/stores/quotations';
import { useQuotationForm } from 'src/pages/05_quotation/form';
import { useDebitNoteForm } from './form';
import { useReceipt, usePayment } from 'stores/payment';
import useProductServiceStore from 'stores/product-service';
import {
  DebitNote,
  DebitNoteStatus,
  DebitNotePayload,
  useDebitNote,
} from 'src/stores/debit-note';
import {
  QuotationStatus,
  PayCondition,
  QuotationPayload,
  ProductRelation,
  ProductServiceList,
} from 'src/stores/quotations/types';
import { useConfigStore } from 'src/stores/config';
import DocumentExpansion from './expansion/DocumentExpansion.vue';
import RemarkExpansion from '../12_debit-note/expansion/RemarkExpansion.vue';
import AdditionalFileExpansion from '../09_task-order/expansion/AdditionalFileExpansion.vue';
import PaymentExpansion from './expansion/PaymentExpansion.vue';
import DebitNoteExpansion from './expansion/DebitNoteExpansion.vue';
import StateButton from 'src/components/button/StateButton.vue';
import ProductExpansion from '../12_debit-note/expansion/ProductExpansion.vue';
import SelectReadyRequestWork from '../09_task-order/SelectReadyRequestWork.vue';
import QuotationFormReceipt from '../05_quotation/QuotationFormReceipt.vue';
import DialogViewFile from 'src/components/dialog/DialogViewFile.vue';
import WorkerItemExpansion from './expansion/WorkerItemExpansion.vue';
import PaymentForm from '../05_quotation/PaymentForm.vue';
import {
  MainButton,
  SaveButton,
  UndoButton,
  EditButton,
  CancelButton,
} from 'src/components/button';
import { RequestWork } from 'src/stores/request-list/types';
import { storeToRefs } from 'pinia';
import useOptionStore from 'src/stores/options';
import {
  canAccess,
  deleteItem,
  dialog,
  dialogWarningClose,
  isRoleInclude,
} from 'src/stores/utils';
import { useI18n } from 'vue-i18n';
import { Employee } from 'src/stores/employee/types';
import QuotationFormWorkerSelect from '../05_quotation/QuotationFormWorkerSelect.vue';
import { watch } from 'vue';
import { ProductTree, quotationProductTree } from '../05_quotation/utils';
import TableRequest from '../05_quotation/TableRequest.vue';
import { RequestData, RequestDataStatus } from 'src/stores/request-list/types';
import { useRequestList } from 'src/stores/request-list';
import { Receipt } from 'src/stores/payment/types';
import {
  Product,
  ProductGroup,
  Service,
} from 'src/stores/product-service/types';
import { precisionRound } from 'src/utils/arithmetic';
import QuotationFormProductSelect from '../05_quotation/QuotationFormProductSelect.vue';
import { getName } from 'src/services/keycloak';

const debitNoteForm = useDebitNoteForm();
const route = useRoute();
const router = useRouter();
const debitNote = useDebitNote();
const configStore = useConfigStore();
const quotationStore = useQuotationStore();
const optionStore = useOptionStore();
const quotationForm = useQuotationForm();
const useReceiptStore = useReceipt();
const productServiceStore = useProductServiceStore();
const $q = useQuasar();
const paymentStore = usePayment();
const { data: config } = storeToRefs(configStore);
const { newWorkerList } = storeToRefs(quotationForm);
const { currentFormData } = storeToRefs(debitNoteForm);
const { t, locale } = useI18n();
const requestStore = useRequestList();

type ProductGroupId = string;

type Node = {
  [key: string]: any;
  opened?: boolean;
  checked?: boolean;
  bg?: string;
  fg?: string;
  icon?: string;
  children?: Node[];
};

const API_BASE_URL = import.meta.env.VITE_API_BASE_URL;
const tempTableProduct = ref<ProductServiceList[]>([]);
const productList = ref<Partial<Record<ProductGroupId, Product[]>>>({});
const serviceList = ref<Partial<Record<ProductGroupId, Service[]>>>({});
const selectedProductGroup = ref<string>('');
const selectedGroupSub = ref<'product' | 'service' | null>(null);
const productGroup = ref<ProductGroup[]>([]);
const agentPrice = ref(false);
const debitNoteData = ref<DebitNote>();
const quotationData = ref<DebitNote['debitNoteQuotation']>();
const view = ref<QuotationStatus>(QuotationStatus.Issued);
const fileList = ref<FileList>();
const receiptList = ref<Receipt[]>([]);
let previousValue: DebitNotePayload | undefined = undefined;

const rowsRequestList = ref<RequestData[]>([]);

const productServiceList = ref<
  Required<QuotationPayload['productServiceList'][number]>[]
>([]);
const productServiceNodes = ref<ProductTree>([]);

const tempPaySplitCount = ref(0);
const tempPaySplit = ref<
  { no: number; amount: number; name?: string; invoice?: boolean }[]
>([]);

const formTaskList = ref<
  {
    requestWorkId: string;
    requestWorkStep?: { requestWork: RequestWork };
  }[]
>([]);

const attachmentList = ref<FileList>();
const fileData = ref<
  {
    name: string;
    progress: number;
    loaded: number;
    total: number;
    url?: string;
  }[]
>([]);
const attachmentData = ref<
  {
    name: string;
    progress: number;
    loaded: number;
    total: number;
    url?: string;
    placeholder?: boolean;
  }[]
>([]);

const statusTabForm = ref<
  {
    title: string;
    status: 'done' | 'doing' | 'waiting';
    handler: () => void;
    active?: () => boolean;
  }[]
>([]);

const productService = computed(() => {
  return selectedInstallmentNo.value.length > 0
    ? productServiceList.value.filter((v) => {
        return (
          v.installmentNo &&
          selectedInstallmentNo.value.includes(v.installmentNo)
        );
      })
    : productServiceList.value;
});

const summaryPrice = computed(() => getPrice(productServiceList.value));

const readonly = computed(
  () =>
    debitNoteData.value?.quotationStatus === QuotationStatus.PaymentSuccess ||
    debitNoteData.value?.quotationStatus === QuotationStatus.ProcessComplete ||
    pageState.mode === 'info',
);

const pageState = reactive({
  mode: 'create' as 'create' | 'edit' | 'info',
  employeeModal: false,
  productDialog: false,
  fileDialog: false,
  productServiceModal: false,
  inputSearchRequest: '',
  statusFilterRequest: 'All' as 'All' | RequestDataStatus,
  imageDialog: false,
  imageDialogTitle: '',
  imageDialogUrl: '',
});

const selectedWorker = ref<
  (Employee & {
    attachment?: {
      name?: string;
      group?: string;
      url?: string;
      file?: File;
      _meta?: Record<string, any>;
    }[];
  })[]
>([]);
const selectedWorkerItem = computed(() => {
  return [
    ...selectedWorker.value.map((e) => ({
      foreignRefNo: e.employeePassport
        ? e.employeePassport[0]?.number || '-'
        : '-',
      employeeName:
        locale.value === Lang.English
          ? `${e.firstNameEN} ${e.lastNameEN}`
          : `${e.firstName || e.firstNameEN} ${e.lastName || e.lastNameEN}`,
      birthDate: dateFormatJS({ date: e.dateOfBirth }),
      gender: e.gender,
      age: calculateAge(e.dateOfBirth),
      nationality: optionStore.mapOption(e.nationality),
      documentExpireDate:
        e.employeePassport !== undefined &&
        e.employeePassport[0]?.expireDate !== undefined
          ? dateFormatJS({ date: e.employeePassport[0]?.expireDate })
          : '-',
      imgUrl: e.selectedImage
        ? `${API_BASE_URL}/employee/${e.id}/image/${e.selectedImage}`
        : '',
      status: e.status,
    })),

    ...newWorkerList.value.map((v: any) => ({
      foreignRefNo: v.passportNo || '-',
      employeeName:
        locale.value === Lang.English
          ? `${v.firstNameEN} ${v.lastNameEN}`
          : `${v.firstName || v.firstNameEN} ${v.lastName || v.lastNameEN}`,
      birthDate: dateFormatJS({ date: v.dateOfBirth }),
      gender: v.gender,
      age: calculateAge(v.dateOfBirth),
      nationality: optionStore.mapOption(v.nationality),
      documentExpireDate: '-',
      imgUrl: '',
      status: 'CREATED',
    })),
  ];
});

const selectedInstallmentNo = ref<number[]>([]);
const installmentAmount = ref<number>(0);

const QUOTATION_STATUS = [
  'Accepted',
  'PaymentPending',
  'PaymentSuccess',
  'ProcessComplete',
];

function covertToNode() {
  productServiceNodes.value = quotationProductTree(
    productServiceList.value,
    agentPrice.value,
    config.value?.vat,
  );
}

watch(
  () => productServiceList.value,
  () => {
    covertToNode();
  },
);

function toggleDeleteProduct(index: number) {
  // product display
  productServiceList.value.splice(index, 1);
  productServiceList.value = [...productServiceList.value];

  // find split count
  tempPaySplitCount.value = Math.max(
    ...productServiceList.value.map((v) => v.installmentNo || 0),
  );
  currentFormData.value.paySplitCount = tempPaySplitCount.value;

  // make split.length === split count
  tempPaySplit.value.splice(currentFormData.value.paySplitCount);
}

async function getAllProduct(
  groupId: string,
  opts?: { force?: boolean; page?: number; pageSize?: number; query?: string },
) {
  selectedGroupSub.value = 'product';
  if (!opts?.force && productList.value[groupId] !== undefined) return;
  const ret = await productServiceStore.fetchListProduct({
    page: opts?.page ?? 1,
    pageSize: opts?.pageSize ?? 9999,
    query: opts?.query,
    productGroupId: groupId,
    activeOnly: true,
  });
  if (ret) productList.value[groupId] = ret.result;
}

async function getAllService(
  groupId: string,
  opts?: { force?: boolean; page?: number; pageSize?: number; query?: string },
) {
  selectedGroupSub.value = 'service';

  if (!opts?.force && serviceList.value[groupId] !== undefined) return;

  const ret = await productServiceStore.fetchListService({
    page: opts?.page ?? 1,
    pageSize: opts?.pageSize ?? 9999,
    productGroupId: groupId,
    query: opts?.query,

    fullDetail: true,
  });
  if (ret) serviceList.value[groupId] = ret.result;
}

async function assignToProductServiceList() {
  const ret = await productServiceStore.fetchProductGroup({
    page: 1,
    pageSize: 9999,
  });

  if (ret) {
    productGroup.value = ret.result;
  }
}

function undo() {
  if (!previousValue) return;

  currentFormData.value = structuredClone(previousValue);
  assignProductServiceList();
  assignSelectedWorker();
  pageState.mode = 'info';
}

function assignProductServiceList() {
  if (!debitNoteData.value) return;
  productServiceList.value = debitNoteData.value.productServiceList.map(
    (v, i) => ({
      id: v.id!,
      installmentNo: v.installmentNo || 0,
      workerIndex: v.worker
        .map((a) =>
          debitNoteData.value!.worker.findIndex(
            (b) => b.employeeId === a.employeeId,
          ),
        )
        .filter(
          (index): index is number => index !== -1 && index !== undefined,
        ),
      vat: v.vat || 0,
      pricePerUnit: v.pricePerUnit || 0,
      discount: v.discount || 0,
      amount: v.amount || 0,
      product: v.product,
      work: v.work || null,
      service: v.service || null,
    }),
  );
}

function assignSelectedWorker() {
  if (debitNoteData.value)
    selectedWorker.value = debitNoteData.value.worker.map((v) => v.employee);
}

async function assignFormData(id: string) {
  const data = await debitNote.getDebitNote(id);
  if (!data) return;

  debitNoteData.value = data;

  selectedProductGroup.value =
    data.productServiceList[0]?.product.productGroup?.id || '';

  ((previousValue = {
    id: data.id || undefined,
    debitNoteQuotationId: data.debitNoteQuotationId || undefined,
    productServiceList: structuredClone(
      data.productServiceList.map((v) => ({
        workerIndex: v.worker.map((a) =>
          data.worker.findIndex((b) => b.employeeId === a.employeeId),
        ),
        installmentNo: v.installmentNo,
        discount: v.discount,
        amount: v.amount,
        workId: v.workId ?? '',
        serviceId: v.serviceId ?? '',
        productId: v.productId,
      })),
    ),
    worker: data.worker.map((v) => v.employee),
    payBillDate: new Date(data.payBillDate),
    paySplitCount: data.paySplitCount,
    payCondition: data.payCondition,
    dueDate: new Date(data.dueDate),
    discount: data.discount,
    agentPrice: data.agentPrice,
    quotationId: data.debitNoteQuotationId,
    remark: data.remark || undefined,
  }),
    (currentFormData.value = structuredClone(previousValue)));

  assignProductServiceList();
  assignSelectedWorker();
  await getQuotation(data.debitNoteQuotation?.id);
  await assignToProductServiceList();
  await fetchRequest();
  await fetchReceipt();

  await initStatus();
}

async function getQuotation(id?: string) {
  const quotationId =
    typeof route.query['quotationId'] === 'string'
      ? route.query['quotationId']
      : id;

  if (!!quotationId) {
    const data = await quotationStore.getQuotation(quotationId);
    if (!!data) {
      quotationData.value = data;
    }
  }
}

function getStatus(
  status: typeof currentFormData.value.quotationStatus,
  doneIndex: number,
  doingIndex: number,
) {
  return QUOTATION_STATUS.findIndex((v) => v === status) >= doneIndex
    ? 'done'
    : QUOTATION_STATUS.findIndex((v) => v === status) >= doingIndex
      ? 'doing'
      : 'waiting';
}

async function initStatus() {
  if (debitNoteData.value?.quotationStatus === QuotationStatus.Issued)
    view.value = QuotationStatus.Issued;

  //TODO แก้สถานะแสดงแยกต่างหาก
  statusTabForm.value = [
    {
      title: 'title',
      status: debitNoteData.value?.id !== undefined ? 'done' : 'doing',
      active: () => view.value === QuotationStatus.Issued,
      handler: () => {
        pageState.mode = 'info';
        view.value = QuotationStatus.Issued;
      },
    },
    {
      title: 'accepted',
      status:
        debitNoteData.value?.id !== undefined
          ? getStatus(debitNoteData.value.quotationStatus, 1, -1)
          : 'waiting',
      active: () => view.value === QuotationStatus.Accepted,
      handler: () => {
        pageState.mode = 'info';
        view.value = QuotationStatus.Accepted;
      },
    },
    {
      title: 'payment',
      status:
        debitNoteData.value?.id !== undefined
          ? getStatus(debitNoteData.value.quotationStatus, 2, 1)
          : 'waiting',
      active: () => view.value === QuotationStatus.PaymentPending,
      handler: async () => {
        view.value = QuotationStatus.PaymentPending;
      },
    },

    {
      title: 'receipt',
      status: getStatus(debitNoteData.value?.quotationStatus, 2, 2),
      active: () => view.value === QuotationStatus.PaymentSuccess,
      handler: () => {
        pageState.mode = 'info';
        view.value = QuotationStatus.PaymentSuccess;
      },
    },

    {
      title: 'processComplete',
      status: getStatus(debitNoteData.value?.quotationStatus, 3, 2),
      active: () => view.value === QuotationStatus.ProcessComplete,
      handler: () => {
        pageState.mode = 'info';
        view.value = QuotationStatus.ProcessComplete;
      },
    },
  ];
}

function goToQuotation() {
  if (!quotationData.value) return;

  const quotation = quotationData.value;
  const url = new URL('/quotation/view', window.location.origin);

  localStorage.setItem(
    'new-quotation',
    JSON.stringify({
      customerBranchId: quotation.customerBranchId,
      agentPrice: quotation.agentPrice,
      statusDialog: 'info',
      quotationId: quotation.id,
    }),
  );

  window.open(url.toString(), '_blank');
}

function getPrice(
  list: typeof productServiceList.value,
  filterHook?: (
    item: (typeof productServiceList.value)[number],
    index?: number,
  ) => boolean,
) {
  if (filterHook) list = list.filter(filterHook);

  return list.reduce(
    (a, c) => {
      if (
        selectedInstallmentNo.value.length > 0 &&
        c.installmentNo &&
        !selectedInstallmentNo.value.includes(c.installmentNo)
      ) {
        return a;
      }

      const price = precisionRound(c.pricePerUnit * c.amount);
      const vat =
        precisionRound(
          (c.pricePerUnit * (c.discount ? c.amount : 1) - c.discount) *
            (config.value?.vat || 0.07),
        ) * (!c.discount ? c.amount : 1);

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

      return a;
    },
    {
      totalPrice: 0,
      totalDiscount: 0,
      vat: 0,
      vatExcluded: 0,
      finalPrice: 0,
    },
  );
}

async function fetchRequest() {
  const res = await requestStore.getRequestDataList({
    query: pageState.inputSearchRequest,
    page: 1,
    pageSize: 999999,
    requestDataStatus:
      pageState.statusFilterRequest === 'All'
        ? undefined
        : pageState.statusFilterRequest,
    quotationId: currentFormData.value.id,
  });

  if (res) {
    rowsRequestList.value = res.result;
  }
}

async function fetchReceipt() {
  const res = await useReceiptStore.getReceiptList({
    debitNoteId: debitNoteData.value?.id || '',
    debitNoteOnly: true,
    quotationOnly: false,
  });

  if (res) {
    receiptList.value = res.result;
  }
}

function viewProductFile(data: ProductRelation) {
  const base64 = data.detail.match(/src="([^"]+)"/);

  pageState.imageDialog = true;
  pageState.imageDialogTitle = data.name;
  pageState.imageDialogUrl = base64 ? base64[1] : '';
}

function convertToTable(nodes: Node[]) {
  const _recursive = (v: Node): Node | Node[] => {
    if (v.checked && v.children) return v.children.flatMap(_recursive);
    if (v.checked) return v;
    return [];
  };
  const list = nodes.flatMap(_recursive).map((v) => v.value);

  currentFormData.value.paySplitCount = Math.max(
    ...list.map((v) => v.installmentNo || 0),
  );
  tempPaySplitCount.value = currentFormData.value.paySplitCount;

  list.forEach((v) => {
    v.amount = Math.max(selectedWorkerItem.value.length, 1);
    if (!v.workerIndex) v.workerIndex = [];
    for (let i = 0; i < selectedWorkerItem.value.length; i++) {
      v.workerIndex.push(i);
    }

    if (!v.installmentNo) {
      v.installmentNo = currentFormData.value.paySplitCount;
    }
  });

  productServiceList.value = list;
  tempTableProduct.value = JSON.parse(JSON.stringify(list));

  currentFormData.value.paySplitCount = 0;
  currentFormData.value.payCondition = PayCondition.Full;

  tempPaySplitCount.value = currentFormData.value.paySplitCount;
  pageState.productServiceModal = false;
}

async function getFileList(debitNoteId: string, slip?: boolean) {
  const list = slip
    ? await debitNote.listFile({
        group: 'slip',
        parentId: debitNoteId,
      })
    : await debitNote.listAttachment({
        parentId: debitNoteId,
      });
  if (list)
    slip
      ? (fileData.value = await Promise.all(
          list.map(async (v) => {
            const rse = await debitNote.headFile({
              group: 'slip',
              parentId: debitNoteId,
              fileId: v,
            });

            let contentLength = 0;
            if (rse) contentLength = Number(rse['content-length']);

            return {
              name: v,
              progress: 1,
              loaded: contentLength,
              total: contentLength,
              url: `/debit-note/${debitNoteId}/file-slip/${v}`,
            };
          }),
        ))
      : (attachmentData.value = await Promise.all(
          list.map(async (v) => {
            const rse = await debitNote.headAttachment({
              parentId: debitNoteId,
              fileId: v,
            });

            let contentLength = 0;
            if (rse) contentLength = Number(rse['content-length']);

            return {
              name: v,
              progress: 1,
              loaded: contentLength,
              total: contentLength,
              url: `/debit-note/${debitNoteId}/attachment/${v}`,
            };
          }),
        ));
}

async function uploadFile(debitNoteId: string, list: FileList, slip?: boolean) {
  const promises: ReturnType<
    typeof debitNote.putAttachment | typeof debitNote.putFile
  >[] = [];

  if (!slip) {
    attachmentData.value = attachmentData.value.filter((v) => !v.placeholder);
  }

  for (let i = 0; i < list.length; i++) {
    const data = {
      name: list[i].name,
      progress: 1,
      loaded: 0,
      total: 0,
      url: `/debit-note/${debitNoteId}/${slip ? 'file-slip' : 'attachment'}/${list[i].name}`,
    };
    promises.push(
      slip
        ? debitNote.putFile({
            group: 'slip',
            parentId: debitNoteId,
            fileId: list[i].name,
            file: list[i],
            uploadUrl: true,
            onUploadProgress: (e) => {
              const exists = fileData?.value.find((v) => v.name === data.name);
              if (!exists) return fileData?.value.push(data);
              exists.total = e.total || 0;
              exists.progress = e.progress || 0;
              exists.loaded = e.loaded;
            },
          })
        : debitNote.putAttachment({
            parentId: debitNoteId,
            name: list[i].name,
            file: list[i],
            onUploadProgress: (e) => {
              const exists = attachmentData?.value.find(
                (v) => v.name === data.name,
              );
              if (!exists) return attachmentData?.value.push(data);
              exists.total = e.total || 0;
              exists.progress = e.progress || 0;
              exists.loaded = e.loaded;
            },
          }),
    );
    slip ? fileData?.value.push(data) : attachmentData?.value.push(data);
  }
  fileList.value = undefined;
  attachmentList.value = undefined;

  const beforeUnloadHandler = (e: Event) => {
    e.preventDefault();
  };

  window.addEventListener('beforeunload', beforeUnloadHandler);

  return await Promise.all(promises).then((v) => {
    window.removeEventListener('beforeunload', beforeUnloadHandler);
    return v;
  });
}

async function remove(debitNoteId: string, n: string, slip?: boolean) {
  dialogWarningClose(t, {
    message: t('dialog.message.confirmDelete'),
    actionText: t('dialog.action.ok'),
    action: async () => {
      const res = slip
        ? await debitNote.delFile({
            group: 'slip',
            parentId: debitNoteId,
            fileId: n,
          })
        : await debitNote.delAttachment({
            parentId: debitNoteId,
            name: n,
          });
      if (res) {
        getFileList(debitNoteId, slip);
      }
    },
    cancel: () => {},
  });
}

async function submit() {
  const payload: DebitNotePayload = {
    id: currentFormData.value.id || undefined,
    productServiceList: productServiceList.value.map((v) => ({
      installmentNo: v.installmentNo,
      workerIndex: v.workerIndex,
      discount: v.discount,
      amount: v.amount,
      productId: v.product.id,
      workId: v.work?.id || '',
      serviceId: v.service?.id || '',
    })),

    worker: JSON.parse(
      JSON.stringify([
        ...selectedWorker.value.map((v) => {
          {
            return v.id;
          }
        }),
        ...newWorkerList.value.map((v) => {
          const { attachment, ...payload } = v;
          return pageState.mode === 'edit' ? payload.id : payload;
        }),
      ]),
    ),
    dueDate: currentFormData.value.dueDate,
    payCondition: currentFormData.value.payCondition,
    discount: currentFormData.value.discount,
    remark: currentFormData.value.remark || undefined,
    agentPrice: agentPrice.value,
    quotationId: quotationData.value?.id || '',
  };

  const res =
    pageState.mode === 'edit'
      ? await debitNote.updateDebitNote(payload)
      : await debitNote.createDebitNote(payload);

  if (res) {
    newWorkerList.value = [];
    await router.push(`/debit-note/${res.id}/?mode=info`);

    if (attachmentList.value && pageState.mode === 'create') {
      await uploadFile(res.id, attachmentList.value, false);
    }

    pageState.mode = 'info';
    assignFormData(res.id);

    initStatus();
  }
}

function toggleMode(mode: 'create' | 'edit' | 'info') {
  const currentMode = mode || route.query.mode;
  const newMode = currentMode; // เปลี่ยนค่า 'edit' เป็น 'view' และกลับกัน

  router.push({
    path: route.path,
    query: { ...route.query, mode: newMode },
  });
}

async function exampleReceipt(id: string) {
  $q.loading.show();
  const url = await paymentStore.getFlowAccount(id);

  if (url) {
    $q.loading.hide();
    window.open(url.data.link, '_blank');
  }
}

function storeDataLocal() {
  //  quotationFormData.value.productServiceList = productServiceList.value;

  localStorage.setItem(
    'debit-note-preview',
    JSON.stringify({
      data: {
        ...currentFormData.value,
        customerBranchId: quotationData.value?.customerBranchId,
        registeredBranchId: quotationData.value?.registeredBranchId,
      },
      meta: {
        source: {
          code: pageState.mode === 'create' ? '-' : debitNoteData.value?.code,
          createAt:
            pageState.mode === 'create'
              ? Date.now()
              : debitNoteData.value?.createdAt,
          createBy: debitNoteData.value?.createdBy,
          payCondition: currentFormData.value.payCondition,
          contactName: quotationData.value?.contactName,
          contactTel: quotationData.value?.contactTel,
          workName: quotationData.value?.workName,
          dueDate: currentFormData.value.dueDate,
        },
        productServicelist: productService.value,
        selectedWorker: selectedWorker.value,
        createdBy: getName(),
      },
    }),
  );

  const url = new URL('/debit-note/document-view', window.location.origin);

  window.open(url, '_blank');
}

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

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

watch(
  () => pageState.mode,
  () => toggleMode(pageState.mode),
);

watch(
  [() => pageState.inputSearchRequest, () => pageState.statusFilterRequest],
  () => {
    fetchRequest();
  },
);

onMounted(async () => {
  initTheme();
  initLang();
  initStatus();

  if (!!route.params['id'] && typeof route.params['id'] === 'string') {
    await assignFormData(route.params['id']);
  }

  if (typeof route.query['quotationId'] === 'string') {
    pageState.mode = 'create';
    await getQuotation(route.query['quotationId']);
  }

  if (typeof route.query['mode'] === 'string') {
    pageState.mode =
      (route.query['mode'] as 'create' | 'edit' | 'info') || 'info';
  }

  if (typeof route.query['tab'] === 'string') {
    view.value =
      {
        payment: QuotationStatus.PaymentPending,
        receipt: QuotationStatus.PaymentSuccess,
      }[route.query['tab']] || QuotationStatus.Issued;
  }

  if (
    pageState.mode === 'edit' &&
    debitNoteData.value?.quotationStatus !== QuotationStatus.Issued
  ) {
    pageState.mode = 'info';
  }
  await useConfigStore().getConfig();
});

async function submitAccepted() {
  dialog({
    color: 'info',
    icon: 'mdi-account-check',
    title: t('dialog.title.confirmDebitNoteAccept'),
    actionText: t('general.confirm'),
    persistent: true,
    message: t('dialog.message.quotationAccept'),
    action: async () => {
      if (!currentFormData.value.id) return;

      const res = await debitNote.action.acceptDebitNote(
        currentFormData.value.id,
      );

      if (res && typeof route.params['id'] === 'string') {
        await assignFormData(route.params['id']);
      }
    },
    cancel: () => {},
  });
}
</script>

<template>
  <div class="column surface-0 fullscreen">
    <div class="color-bar" :class="{ ['dark']: $q.dark.isActive }">
      <div :class="{ ['indigo-segment']: true }"></div>
      <div :class="{ ['light-indigo-segment']: true }"></div>
      <div class="white-segment"></div>
    </div>

    <!-- SEC: Header -->
    <header
      class="row q-px-md q-py-sm items-center justify-between relative-position"
    >
      <section class="banner" :class="{ dark: $q.dark.isActive }"></section>
      <div style="flex: 1" class="row items-center">
        <RouterLink to="/debit-note">
          <q-img src="/icons/favicon-512x512.png" width="3rem" />
        </RouterLink>
        <span class="column text-h6 text-bold q-ml-md">
          {{ $t('debitNote.title') }}
          <!-- {{ code || '' }} -->
          <span class="text-caption text-regular app-text-muted">
            {{
              $t('quotation.processOn', {
                msg: dateFormatJS({
                  date: debitNoteData?.createdAt || new Date(Date.now()),
                  monthStyle: 'long',
                }),
              })
            }}
          </span>
        </span>
      </div>
    </header>

    <!-- SEC: Body -->
    <article
      class="col full-width q-pa-md"
      style="flex-grow: 1; overflow-y: auto"
    >
      <section class="col-sm col-12">
        <div class="col q-gutter-y-md">
          <nav
            class="surface-1 q-pa-sm row no-wrap full-width scroll rounded"
            style="gap: 10px"
          >
            <StateButton
              v-for="i in statusTabForm"
              :key="i.title"
              :label="
                $t(
                  `debitNote${i.title === 'title' ? '' : '.viewMode'}.${i.title}`,
                )
              "
              :status-active="i.active?.()"
              :status-done="i.status === 'done'"
              :status-waiting="i.status === 'waiting'"
              @click="i.handler()"
            />
          </nav>
          <!-- #TODO  add goToQuotation as @goto-quotation-->

          <DocumentExpansion
            v-if="
              view === QuotationStatus.Issued ||
              view === QuotationStatus.Accepted
            "
            :readonly
            :registered-branch-id="quotationData?.registeredBranchId"
            :customer-id="quotationData?.customerBranchId"
            :quotation-code="quotationData?.code || '-'"
            :quotation-work-name="quotationData?.workName || '-'"
            :quotation-contact-name="quotationData?.contactName || '-'"
            :quotation-contact-tel="quotationData?.contactTel || '-'"
            v-model:due-date="currentFormData.dueDate"
            @goto-quotation="() => goToQuotation()"
          />

          <DebitNoteExpansion
            v-if="false"
            :readonly
            v-model:reason="currentFormData.reason"
            v-model:detail="currentFormData.detail"
          />

          <PaymentForm
            v-if="view === QuotationStatus.PaymentPending"
            is-debit-note
            :readonly="isRoleInclude(['sale', 'head_of_sale'])"
            :data="debitNoteData"
            @fetch-status="
              () => {
                if (!!debitNoteData) assignFormData(debitNoteData?.id);
              }
            "
          />

          <WorkerItemExpansion
            v-if="
              view === QuotationStatus.Issued ||
              view === QuotationStatus.Accepted
            "
            :readonly
            :hide-btn-add-worker="
              !readonly &&
              (!currentFormData || currentFormData.quotationStatus === 'Issued')
            "
            :row-worker="selectedWorkerItem"
            @add-worker="() => (pageState.employeeModal = true)"
            @delete="(i) => deleteItem(selectedWorker, i)"
          />

          <!-- #TODO add  openProductDialog at @add-product-->
          <ProductExpansion
            v-if="
              view === QuotationStatus.Issued ||
              view === QuotationStatus.Accepted
            "
            :readonly
            :installment-input="currentFormData.payCondition === 'SplitCustom'"
            :max-installment="currentFormData.paySplitCount"
            :agent-price="agentPrice"
            :employee-rows="selectedWorkerItem"
            :rows="productService"
            @add-product="
              () => {
                pageState.productServiceModal = true;
                covertToNode();
              }
            "
            @update-rows="
              (v) => {
                view === null && (productServiceList = v);
              }
            "
            @delete="toggleDeleteProduct"
            @view-file="viewProductFile"
          />

          <PaymentExpansion
            v-if="
              view === QuotationStatus.Issued ||
              view === QuotationStatus.Accepted
            "
            :total-price="summaryPrice.finalPrice"
            :pay-split="[]"
            class="q-mb-md"
            v-model:pay-type="currentFormData.payCondition"
            v-model:pay-split-count="currentFormData.paySplitCount"
            v-model:final-discount="currentFormData.discount"
            v-model:pay-bill-date="currentFormData.payBillDate"
            v-model:summary-price="summaryPrice"
          />

          <!-- TODO: bind additional file -->
          <AdditionalFileExpansion
            v-if="
              view === QuotationStatus.Issued ||
              view === QuotationStatus.Accepted ||
              view === QuotationStatus.PaymentPending
            "
            :readonly="isRoleInclude(['sale', 'head_of_sale'])"
            v-model:file-data="attachmentData"
            :transform-url="
              async (url: string) => {
                const result = await api.get<string>(url);
                return result.data;
              }
            "
            @fetch-file-list="
              () => {
                if (!debitNoteData) return;
                getFileList(debitNoteData.id);
              }
            "
            @upload="
              async (f) => {
                attachmentList = f;
                attachmentData = [];

                Array.from(f).forEach(({ name }) => {
                  attachmentData.push({
                    name: name,
                    progress: 1,
                    loaded: 0,
                    total: 0,
                    placeholder: true,
                  });
                });

                if (!debitNoteData) return;

                await uploadFile(debitNoteData.id, f);
              }
            "
            @remove="
              async (n) => {
                if (!debitNoteData) return;
                await remove(debitNoteData.id, n);
              }
            "
          />

          <RemarkExpansion
            v-if="
              view === QuotationStatus.Issued ||
              view === QuotationStatus.Accepted ||
              view === QuotationStatus.PaymentPending
            "
            :readonly="readonly"
            :final-price="summaryPrice.finalPrice"
            :selected-worker
            v-model:remark="currentFormData.remark"
          />

          <main
            v-if="view === QuotationStatus.ProcessComplete"
            class="surface-1 q-pa-md full-width q-gutter-y-md rounded"
          >
            <div class="row justify-between items-center">
              <q-input
                for="input-search"
                outlined
                dense
                :label="$t('general.search')"
                class="col-12 col-md-3"
                :bg-color="$q.dark.isActive ? 'dark' : 'white'"
                v-model="pageState.inputSearchRequest"
                debounce="200"
              >
                <template #prepend>
                  <q-icon name="mdi-magnify" />
                </template>
              </q-input>

              <q-select
                v-model="pageState.statusFilterRequest"
                outlined
                dense
                option-value="value"
                option-label="label"
                map-options
                emit-value
                :for="'field-select-status'"
                :hide-dropdown-icon="$q.screen.lt.sm"
                :options="[
                  {
                    label: $t('general.all'),
                    value: 'All',
                  },
                  {
                    label: $t('requestList.status.Pending'),
                    value: RequestDataStatus.Pending,
                  },
                  {
                    label: $t('requestList.status.InProgress'),
                    value: RequestDataStatus.InProgress,
                  },
                  {
                    label: $t('requestList.status.Completed'),
                    value: RequestDataStatus.Completed,
                  },
                ]"
              ></q-select>
            </div>
            <TableRequest :rows="rowsRequestList" />
          </main>

          <template v-if="view === QuotationStatus.PaymentSuccess">
            <QuotationFormReceipt
              hide-view-btn
              v-for="(v, i) in receiptList"
              :key="i"
              :amount="v.amount"
              :date="v.date"
              :pay-type="quotationData?.payCondition"
              :index="i"
              :pay-split-count="quotationData?.paySplitCount || 0"
              @view="
                () => {
                  if (quotationData?.payCondition !== 'Full') {
                    selectedInstallmentNo = [v.invoice.installments[0].no];
                    installmentAmount = v.invoice.amount;
                  }

                  view = QuotationStatus.Issued;
                }
              "
              @example="() => exampleReceipt(v.id)"
            />
          </template>
        </div>
      </section>
    </article>

    <!-- SEC: footer -->
    <footer class="surface-1 q-pa-md full-width">
      <nav class="row justify-end">
        <!-- TODO: view example -->
        <MainButton
          class="q-mr-auto"
          outlined
          icon="mdi-play-box-outline"
          color="207 96% 32%"
          @click="storeDataLocal()"
        >
          {{ $t('general.view', { msg: $t('general.example') }) }}
        </MainButton>

        <CancelButton
          outlined
          id="btn-close"
          @click="closeTab()"
          :label="$t('dialog.action.close')"
          v-if="
            (pageState.mode === 'info' || pageState.mode === 'create') &&
            closeAble()
          "
        />

        <div class="row q-gutter-x-sm q-ml-xs">
          <UndoButton
            outlined
            v-if="pageState.mode === 'edit'"
            @click="undo()"
          />
          <SaveButton
            v-if="pageState.mode !== 'info'"
            :disabled="
              selectedWorkerItem.length === 0 && productService.length === 0
            "
            @click="submit"
            solid
          />

          <template v-if="debitNoteData">
            <EditButton
              v-if="
                pageState.mode === 'info' &&
                view === QuotationStatus.Issued &&
                debitNoteData.quotationStatus === QuotationStatus.Issued
              "
              class="no-print"
              solid
              @click="pageState.mode = 'edit'"
            />

            <MainButton
              v-if="
                view === QuotationStatus.Accepted &&
                debitNoteData.quotationStatus === QuotationStatus.Issued
              "
              solid
              icon="mdi-account-multiple-check-outline"
              color="207 96% 32%"
              id="btn-submit-accepted"
              @click="
                () => {
                  submitAccepted();
                }
              "
            >
              {{ $t('quotation.customerAcceptance') }}
            </MainButton>
          </template>
        </div>
      </nav>
    </footer>
  </div>

  <!-- SEC: Dialog -->
  <!-- add employee quotation -->

  <QuotationFormWorkerSelect
    :preselect-worker="selectedWorker"
    :customerBranchId="quotationData?.customerBranchId"
    v-model:open="pageState.employeeModal"
    v-model:new-worker-list="newWorkerList"
    @success="
      (v) => {
        selectedWorker = v.worker;
      }
    "
  />

  <!-- add product service -->
  <QuotationFormProductSelect
    v-model="pageState.productServiceModal"
    v-model:nodes="productServiceNodes"
    v-model:product-group="productGroup"
    v-model:product-list="productList"
    v-model:service-list="serviceList"
    v-model:selected-product-group="selectedProductGroup"
    :agent-price="agentPrice"
    @submit="convertToTable"
    @select-group="
      async (id) => {
        await getAllService(id);
        await getAllProduct(id);
      }
    "
    @search="
      (id, text, mode) => {
        if (mode === 'service') {
          getAllService(id, { force: true, query: text, pageSize: 50 });
        }
        if (mode === 'product') {
          getAllProduct(id, { force: true, query: text, pageSize: 50 });
        }
      }
    "
  ></QuotationFormProductSelect>

  <SelectReadyRequestWork
    v-if="quotationData"
    creditNote
    :fetch-params="{ cancelOnly: true, quotationId: quotationData.id }"
    v-model:open="pageState.productDialog"
    v-model:task-list="formTaskList"
  />

  <DialogViewFile
    hide-tab
    download
    v-model="pageState.fileDialog"
    :url="fileData[0]?.url"
    :transform-url="
      async (url: string) => {
        const result = await api.get<string>(url);
        return result.data;
      }
    "
  />
</template>

<style scoped>
.color-bar {
  width: 100%;
  height: 1vh;
  background: linear-gradient(
    90deg,
    rgb(47, 68, 173) 0%,
    rgba(255, 255, 255, 1) 77%,
    rgba(204, 204, 204, 1) 100%
  );
  display: flex;
  overflow: hidden;
}

.color-bar.dark {
  opacity: 0.7;
}

.indigo-segment {
  background-color: var(--cyan-7);
  flex-grow: 4;
}

.light-indigo-segment {
  background-color: hsla(var(--indigo-10-hsl) / 0.2);
  flex-grow: 0.5;
}

.white-segment {
  background-color: #ffffff;
  flex-grow: 1;
}

.indigo-segment,
.light-indigo-segment,
.white-segment {
  transform: skewX(-60deg);
}

.banner {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: url('/images/building-banner.png');
  background-repeat: no-repeat;
  background-size: cover;
  z-index: -1;

  &.dark {
    filter: invert(100%);
  }
}
</style>
