import { ref } from 'vue';
import { defineStore } from 'pinia';
import { Pagination } from '../types';
import { api } from 'src/boot/axios';
import { Status } from 'stores/types';
import {
  Employee,
  EmployeeCheckup,
  EmployeeCreate,
  EmployeeOther,
  EmployeeWork,
  EmployeeCheckupCreate,
  EmployeeOtherCreate,
  EmployeeWorkCreate,
  EmployeeVisaPayload,
} from './types';
import { CustomerBranch } from '../customer/types';
import useFlowStore from '../flow';
import { baseUrl, manageFile, manageMeta } from '../utils';

const useEmployeeStore = defineStore('api-employee', () => {
  const flowStore = useFlowStore();
  const data = ref<Pagination<Employee[]>>();
  const globalOption = ref();
  const ownerOption = ref<CustomerBranch[]>();
  const fileManager = manageFile<'passport' | 'visa' | 'in-country-notice'>(
    api,
    'employee',
  );
  const metaManager = manageMeta<'passport' | 'visa' | 'in-country-notice'>(
    api,
    'employee',
  );

  async function fetchById(id: string) {
    const res = await api.get<Employee>(`/employee/${id}`);
    if (res && res.status === 200) {
      return res.data;
    }
    return false;
  }

  async function fetchList(opts?: {
    page?: number;
    pageSize?: number;
    query?: string;
    gender?: string;
    status?: Status;
    zipCode?: string;
    customerId?: string;
  }) {
    const params = new URLSearchParams();

    for (const [k, v] of Object.entries(opts || {})) {
      v !== undefined && params.append(k, v.toString());
    }

    const query = params.toString();

    const res = await api.get<Pagination<Employee[]>>(
      `/employee${(params && '?'.concat(query)) || ''}`,
      {
        headers: { 'X-Rtid': flowStore.rtid },
      },
    );

    if (res && res.status === 200) {
      data.value = res.data;
      return data.value;
    }
    return false;
  }

  async function fetchImageListById(
    id: string,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.get(`/employee/${id}/image`, {
      headers: {
        'X-Session-Id': flow?.sessionId,
        'X-Rtid': flow?.refTransactionId || flowStore.rtid,
        'X-Tid': flow?.transactionId,
      },
    });

    if (!res) return false;
    if (res.status === 200) return res.data;
    if (res.status === 204) return null;

    return false;
  }

  async function addImageList(file: File, customerId: string, name: string) {
    await api
      .put(`/employee/${customerId}/image/${name}`, file, {
        headers: { 'Content-Type': file.type },
        onUploadProgress: (e) => console.log(e),
      })
      .catch((e) => console.error(e));

    return name;
  }

  async function deleteImageByName(
    id: string,
    name: string,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.delete(`/employee/${id}/image/${name}`, {
      headers: {
        'X-Session-Id': flow?.sessionId,
        'X-Rtid': flow?.refTransactionId || flowStore.rtid,
        'X-Tid': flow?.transactionId,
      },
    });

    if (!res) return false;
  }

  async function create(
    data: EmployeeCreate,
    imgList: {
      selectedImage: string;
      list: { url: string; imgFile: File | null; name: string }[];
    },
  ) {
    console.log(data);
    const {
      id,
      code,
      image,
      file,
      zipCode,
      employeeWork,
      employeeCheckup,
      ...payload
    } = data;
    const res = await api.post<
      Employee & { profileImageUrl: string; profileImageUploadUrl: string }
    >(
      '/employee',
      { ...payload, selectedImage: imgList.selectedImage },
      {
        headers: { 'X-Rtid': flowStore.rtid },
      },
    );

    if (!res) return false;

    if (res.data.id) {
      if (file) {
        const attachmentUpload = file.map(async ({ group, file, _meta }) => {
          if (file)
            if (file) {
              const _name = file.name;
              const _ext = _name.split('.').at(-1);

              let filename = (group || 'other') + '-' + Date.now();

              if (_ext) filename = filename + '.' + _ext;

              if (group !== undefined && _meta !== undefined) {
                metaManager.postMeta({
                  parentId: res.data.id,
                  group: group as 'passport' | 'visa' | 'in-country-notice',
                  meta: _meta,
                  file,
                });
              }
            }
        });
        await Promise.all(attachmentUpload);
      }
      if (imgList.list.length > 0 && res.data.id) {
        for (let index = 0; index < imgList.list.length; index++) {
          const imgFile = imgList.list[index].imgFile;
          if (imgFile)
            await addImageList(imgFile, res.data.id, imgList.list[index].name);
        }
      }
    }

    return res.data;
  }

  async function createEmployeeCheckup(
    employeeId: string,
    data: EmployeeCheckupCreate,
  ) {
    const { id, statusSave, ...payload } = data;
    const res = await api.post<EmployeeCheckupCreate>(
      `/employee/${employeeId}/checkup`,
      { ...payload },
      { headers: { 'X-Rtid': flowStore.rtid } },
    );

    if (!res) return false;

    return res.data;
  }

  async function createEmployeeWork(
    employeeId: string,
    data: EmployeeWorkCreate,
  ) {
    const { id, ...payload } = data;
    const res = await api.post<EmployeeWorkCreate>(
      `/employee/${employeeId}/work`,
      { ...payload },
      { headers: { 'X-Rtid': flowStore.rtid } },
    );

    if (!res) return false;

    return res.data;
  }

  async function createEmployeeOtherInfo(
    employeeId: string,
    data: EmployeeOtherCreate,
  ) {
    const { id, statusSave, ...payload } = data;
    const res = await api.post<EmployeeOtherCreate>(
      `/employee/${employeeId}/other-info`,
      { ...payload },
      {
        headers: { 'X-Rtid': flowStore.rtid },
      },
    );

    if (!res) return false;

    return res.data;
  }

  async function editByIdEmployeeCheckup(
    employeeOfId: string,
    data: Partial<EmployeeCheckupCreate>,
  ) {
    const {
      id,
      createdAt,
      createdByUserId,
      employeeId,
      statusSave,
      updatedAt,
      updatedByUserId,
      ...payload
    } = data;
    const res = await api.put<EmployeeCheckupCreate>(
      `/employee/${employeeOfId}/checkup/${id}`,
      { ...payload },
      { headers: { 'X-Rtid': flowStore.rtid } },
    );

    if (!res) return false;

    return res.data;
  }

  async function editByIdEmployeeWork(
    employeeOfId: string,
    data: Partial<EmployeeWorkCreate>,
  ) {
    const {
      id,
      createdAt,
      createdByUserId,
      employeeId,
      statusSave,
      updatedAt,
      updatedByUserId,
      ...payload
    } = data;
    const res = await api.put<EmployeeWorkCreate>(
      `/employee/${employeeOfId}/work/${id}`,
      { ...payload },
      { headers: { 'X-Rtid': flowStore.rtid } },
    );

    if (!res) return false;

    return res.data;
  }

  async function editByIdEmployeeOtherInfo(
    employeeOfId: string,
    data: Partial<EmployeeOtherCreate>,
  ) {
    const {
      id,
      statusSave,
      updatedByUserId,
      updatedAt,
      createdByUserId,
      createdAt,
      employeeId,
      ...payload
    } = data;
    const res = await api.put<EmployeeOtherCreate>(
      `/employee/${employeeOfId}/other-info/${id}`,
      { ...payload },
      { headers: { 'X-Rtid': flowStore.rtid } },
    );

    if (!res) return false;

    return res.data;
  }

  async function editById(employeeId: string, data: Partial<EmployeeCreate>) {
    const { id, code, image, file, ...payload } = data;
    const res = await api.put<
      Employee & { imageUrl: string; profileImageUploadUrl: string }
    >(`/employee/${employeeId}`, payload, {
      headers: { 'X-Rtid': flowStore.rtid },
    });

    if (!res) return false;

    if (image) {
      await api
        .put(`/employee/${employeeId}/image`, image, {
          headers: { 'Content-Type': image?.type },
          onUploadProgress: (e) => console.log(e),
        })
        .catch((e) => console.error(e));
    }
    if (file) {
      const attachmentUpload = file.map(async ({ group, file }) => {
        if (file) {
          const _name = file.name;
          const _ext = _name.split('.').at(-1);

          let filename = (group || 'other') + '-' + Date.now();

          if (_ext) filename = filename + '.' + _ext;

          await uploadAttachment(employeeId, file, filename);
        }
      });
      await Promise.all(attachmentUpload);
    }

    return res.data;
  }

  async function deleteByIdCheckUp(opts: {
    employeeId: string;
    checkUpId?: string;
  }) {
    const res = await api.delete<Employee>(
      `/employee/${opts.employeeId}/checkup/${opts.checkUpId}`,
      { headers: { 'X-Rtid': flowStore.rtid } },
    );

    if (!res) return false;
    if (res.status === 200) return res.data;

    return false;
  }

  async function deleteByIdWork(opts: { employeeId: string; workId?: string }) {
    const res = await api.delete<Employee>(
      `/employee/${opts.employeeId}/work/${opts.workId}`,
      {
        headers: { 'X-Rtid': flowStore.rtid },
      },
    );

    if (!res) return false;
    if (res.status === 200) return res.data;

    return false;
  }

  async function deleteById(id: string) {
    const res = await api.delete<Employee>(`/employee/${id}`, {
      headers: { 'X-Rtid': flowStore.rtid },
    });

    if (!res) return false;
    if (res.status === 200) return res.data;

    return false;
  }

  async function fetchCheckup(id: string) {
    const res = await api.get<EmployeeCheckup[]>(`/employee/${id}/checkup`, {
      headers: { 'X-Rtid': flowStore.rtid },
    });
    if (res && res.status === 200) {
      return res.data;
    }
  }

  async function fetchWork(id: string) {
    const res = await api.get<EmployeeWork[]>(`/employee/${id}/work`, {
      headers: { 'X-Rtid': flowStore.rtid },
    });
    if (res && res.status === 200) {
      return res.data;
    }
  }

  async function fetchOther(id: string) {
    const res = await api.get<EmployeeOther>(`/employee/${id}/other-info`, {
      headers: { 'X-Rtid': flowStore.rtid },
    });
    if (res && res.status === 200) {
      return res.data;
    }
  }

  async function getStatsEmployee(customerBranchId?: string) {
    const res = await api.get(
      `/employee/stats${customerBranchId ? '?customerBranchId=' + customerBranchId : ''}/`,
      {
        headers: { 'X-Rtid': flowStore.rtid },
      },
    );
    if (res && res.status === 200) {
      return res.data;
    }
  }

  async function getStatsEmployeeGender(opts?: {
    customerBranchId?: string;
    status?: 'CREATED' | 'ACTIVE' | 'INACTIVE';
    query?: string;
  }) {
    const params = new URLSearchParams();

    for (const [k, v] of Object.entries(opts || {})) {
      v !== undefined && params.append(k, v.toString());
    }

    const query = params.toString();

    const res = await api.get(
      `/employee/stats/gender${(params && '?'.concat(query)) || ''}`,
      {
        headers: { 'X-Rtid': flowStore.rtid },
      },
    );
    if (res && res.status === 200) {
      return res.data;
    }
  }

  async function getEditHistory(employeeId: string) {
    const res = await api.get(`/employee/${employeeId}/edit-history`, {
      headers: { 'X-Rtid': flowStore.rtid },
    });
    if (res && res.status === 200) {
      return res.data;
    }
  }

  async function listAttachment(employeeId: string) {
    const res = await api.get<string[]>(`/employee/${employeeId}/attachment`);
    return !res || res.status >= 400 ? false : res.data;
  }
  async function getAttachment(
    employeeId: string,
    filename: string,
    download = false,
  ) {
    const url = `${baseUrl}/employee/${employeeId}/attachment/${filename}`;
    const res = await api.get<string>(url);

    if (download) {
      fetch(res.data)
        .then(async (res) => await res.blob())
        .then((blob) => {
          const a = document.createElement('a');
          a.download = filename;
          a.href = window.URL.createObjectURL(blob);
          a.click();
          a.remove();
        });
    }

    return res.data;
  }
  async function uploadAttachment(
    employeeId: string,
    file: File,
    filename?: string,
  ) {
    const res = await api.put(
      `/employee/${employeeId}/attachment/${filename || file.name}`,
      file,
      {
        headers: {
          'X-Rtid': flowStore.rtid,
          'Content-Type': file.type,
        },
      },
    );
    return !(!res || res.status >= 400);
  }

  async function deleteAttachment(employeeId: string, filename: string) {
    const res = await api.delete(
      `/employee/${employeeId}/attachment/${filename}`,
      { headers: { 'X-Rtid': flowStore.rtid } },
    );
    return !(!res || res.status >= 400);
  }

  async function attachment(opts: {
    action: 'get' | 'put' | 'delete';
    type: 'passport' | 'visa' | 'in-country-notice';
    id: string;
  }) {
    const res = await api[opts.action](
      `/employee/file-${opts.type}/${opts.id}`,
    );

    if (res) return res.data;
  }

  async function listPassport(employeeId: string) {
    const res = await api.get(`/employee/${employeeId}/passport`, {
      headers: { 'X-Rtid': flowStore.rtid },
    });

    if (res && res.status < 400) return res.data;

    return false;
  }

  return {
    data,
    globalOption,
    ownerOption,

    fetchById,
    fetchList,

    fetchImageListById,
    addImageList,
    deleteImageByName,

    create,
    editById,
    deleteById,
    fetchCheckup,
    fetchWork,
    fetchOther,
    getStatsEmployee,
    getStatsEmployeeGender,
    getEditHistory,

    createEmployeeCheckup,
    editByIdEmployeeCheckup,
    deleteByIdCheckUp,

    createEmployeeWork,
    editByIdEmployeeWork,
    deleteByIdWork,

    createEmployeeOtherInfo,
    editByIdEmployeeOtherInfo,

    listAttachment,
    getAttachment,
    uploadAttachment,
    deleteAttachment,

    attachment,

    listPassport,
    ...fileManager,
    ...metaManager,
  };
});

export default useEmployeeStore;
