import { ref } from 'vue';
import { defineStore } from 'pinia';
import { Pagination, Status } from '../types';
import { api } from 'src/boot/axios';

import {
  RoleData,
  User,
  UserAttachment,
  UserAttachmentCreate,
  UserAttachmentDelete,
  UserCreate,
  UserOption,
} from './types';
import axios from 'axios';
import useBranchStore from '../branch';
import { Branch } from '../branch/types';
import useFlowStore from '../flow';

const branchStore = useBranchStore();

const useUserStore = defineStore('api-user', () => {
  const flowStore = useFlowStore();
  const userOption = ref<UserOption>({
    hqOpts: [],
    brOpts: [],
    roleOpts: [],
    userTypeOpts: [
      { label: 'USER', value: 'USER' },
      { label: 'MESSENGER', value: 'MESSENGER' },
      { label: 'DELEGATE', value: 'DELEGATE' },
      { label: 'AGENCY', value: 'AGENCY' },
    ],
    genderOpts: [],
    responsibleAreaOpts: [],
    nationalityOpts: [],
    trainingPlaceOpts: [],
  });

  const data = ref<Pagination<User[]>>();

  async function fetchHqOption() {
    if (userOption.value.hqOpts.length === 0) {
      const res = await branchStore.fetchList({
        pageSize: 999,
        filter: 'head',
      });
      if (res) {
        res.result.map((item) => {
          userOption.value.hqOpts.push({
            label: item.code,
            value: item.id,
          });
        });
      }
    }
  }

  async function fetchBrOption(id: string) {
    const res = await branchStore.fetchById(id, {
      includeSubBranch: true,
    });

    if (res && res.branch) {
      res.branch.forEach((item) => {
        const exists = userOption.value.brOpts.some(
          (opt) => opt.value === item.id,
        );

        if (!exists) {
          userOption.value.brOpts.push({
            label: item.code,
            value: item.id,
          });
        }
      });
    }
  }

  async function fetchRoleOption() {
    const res = await api.get<RoleData[]>('/keycloak/role');
    res.data.map((item) => {
      const formattedName = item.name
        .replace(/_/g, ' ')
        .toLowerCase()
        .split(' ')
        .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
        .join(' ');
      userOption.value.roleOpts.push({
        label: formattedName,
        value: item.name,
      });
    });
  }

  async function fetchAttachment(
    userId: string,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.get<UserAttachment[]>(`/user/${userId}/attachment`, {
      headers: {
        'X-Session-Id': flow?.sessionId,
        'X-Rtid': flow?.refTransactionId || flowStore.rtid,
        'X-Tid': flow?.transactionId,
      },
    });

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

  async function addAttachment(
    userId: string,
    payload: UserAttachmentCreate,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const list: { name: string; file: File }[] = [];

    payload.file.forEach((v) => {
      let filename = v.name;

      if (list.some((v) => v.name === filename)) {
        const dotIndex = filename.lastIndexOf('.');
        const originalName =
          dotIndex !== -1 && !filename.startsWith('.')
            ? filename.slice(0, dotIndex)
            : filename;
        const extension =
          dotIndex !== -1 && !filename.startsWith('.')
            ? filename.slice(dotIndex)
            : '';

        let i = 0;

        while (list.some((v) => v.name === filename)) {
          filename = `${originalName} (${++i})`;
          if (dotIndex !== -1) filename += extension;
        }
      }

      list.push({ name: filename, file: v });
    });

    const res = await api.post<(UserAttachment & { uploadUrl: string })[]>(
      `/user/${userId}/attachment`,
      { file: list.map((v) => v.name) },
      {
        headers: {
          'X-Session-Id': flow?.sessionId,
          'X-Rtid': flow?.refTransactionId || flowStore.rtid,
          'X-Tid': flow?.transactionId,
        },
      },
    );

    await Promise.all(
      res.data.map(async (a) => {
        const found = list.find((b) => b.name === a.name)!;

        await axios
          .put(a.uploadUrl, found.file, {
            headers: { 'Content-Type': found.file.type },
            onUploadProgress: (e) => console.log(e),
          })
          .catch((e) => console.error(e));
      }),
    );
  }

  async function deleteAttachment(
    userId: string,
    payload: UserAttachmentDelete,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    await api.delete(`/user/${userId}/attachment`, {
      data: payload,
      headers: {
        'X-Session-Id': flow?.sessionId,
        'X-Rtid': flow?.refTransactionId || flowStore.rtid,
        'X-Tid': flow?.transactionId,
      },
    });
  }

  async function fetchList(
    opts?: {
      page?: number;
      pageSize?: number;
      zipCode?: string;
      query?: string;
      includeBranch?: boolean;
      userType?: string;
      status?: Status;
    },
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const params = new URLSearchParams();

    if (opts?.pageSize && opts?.pageSize > 0) {
      params.append('pageSize', `${opts.pageSize}`);
    }
    if (opts?.page && opts.page > 0) params.append('page', `${opts.page}`);
    if (opts?.zipCode) params.append('zipCode', opts.zipCode);
    if (opts?.query) params.append('query', opts.query);
    if (opts?.includeBranch) params.append('includeBranch', 'true');
    if (opts?.userType) params.append('userType', opts.userType);
    if (opts?.status) params.append('status', opts.status);

    const query = params.toString();

    const res = await api.get<Pagination<User[]>>(
      `/user${(params && '?'.concat(query)) || ''}`,
      {
        headers: {
          'X-Session-Id': flow?.sessionId,
          'X-Rtid': flow?.refTransactionId || flowStore.rtid,
          'X-Tid': flow?.transactionId,
        },
      },
    );

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

  async function fetchById(
    id: string,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.get<User>(`/user/${id}`, {
      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 fetchImageListById(
    id: string,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.get(`/user/${id}/profile-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, userId: string, name: string) {
    await api
      .put(`/user/${userId}/profile-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(`/user/${id}/profile-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: UserCreate,
    imgList: {
      selectedImage: string;
      list: { url: string; imgFile: File | null; name: string }[];
    },
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const { zipCode, ...payload } = data;
    const res = await api.post<User>(
      '/user',
      {
        ...payload,
        selectedImage: imgList.selectedImage || '',
      },
      {
        headers: {
          'X-Session-Id': flow?.sessionId,
          'X-Rtid': flow?.refTransactionId || flowStore.rtid,
          'X-Tid': flow?.transactionId,
        },
      },
    );

    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);
      }
    }

    if (!res) return false;

    return res.data;
  }

  async function editById(
    id: string,
    data: Partial<UserCreate & { status?: 'ACTIVE' | 'INACTIVE' }>,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.put<User>(`/user/${id}`, data, {
      headers: {
        'X-Session-Id': flow?.sessionId,
        'X-Rtid': flow?.refTransactionId || flowStore.rtid,
        'X-Tid': flow?.transactionId,
      },
    });

    if (!res) return false;

    return res.data;
  }

  async function deleteById(
    id: string,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.delete<User>(`/user/${id}`, {
      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;

    return false;
  }

  async function getBranch(
    userId: string,
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.get<Pagination<Branch[]>>(`/user/${userId}/branch`, {
      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;

    return false;
  }

  async function addBranch(
    userId: string,
    branchId: string | string[],
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.post(
      `/user/${userId}/branch`,
      { branch: ([] as string[]).concat(branchId) },
      {
        headers: {
          'X-Session-Id': flow?.sessionId,
          'X-Rtid': flow?.refTransactionId || flowStore.rtid,
          'X-Tid': flow?.transactionId,
        },
      },
    );

    if (!res) return false;
    if (res.status >= 400) return false;

    return res.data || true;
  }

  async function removeBranch(
    userId: string,
    branchId: string | string[],
    flow?: {
      sessionId?: string;
      refTransactionId?: string;
      transactionId?: string;
    },
  ) {
    const res = await api.delete(`/user/${userId}/branch`, {
      headers: {
        'X-Session-Id': flow?.sessionId,
        'X-Rtid': flow?.refTransactionId || flowStore.rtid,
        'X-Tid': flow?.transactionId,
      },
      data: { branch: ([] as string[]).concat(branchId) },
    });

    if (!res) return false;
    if (res.status >= 400) return false;

    return res.data || true;
  }

  async function typeStats(flow?: {
    sessionId?: string;
    refTransactionId?: string;
    transactionId?: string;
  }) {
    const res = await api.get('/user/type-stats', {
      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;

    return false;
  }

  return {
    data,
    userOption,

    fetchHqOption,
    fetchBrOption,
    fetchRoleOption,

    fetchList,
    fetchById,

    fetchImageListById,
    addImageList,
    deleteImageByName,

    create,
    editById,
    deleteById,

    getBranch,
    addBranch,
    removeBranch,

    fetchAttachment,
    addAttachment,
    deleteAttachment,

    typeStats,
  };
});

export default useUserStore;
