import { ref, watch } from 'vue';
import { defineStore } from 'pinia';

import { api } from 'src/boot/axios';
import useFlowStore from '../flow';
import { Pagination } from '../types';
import { BankBook, Branch, BranchCreate } from './types';
import { BranchContact } from '../branch-contact/types';
import { User } from '../user/types';

type BranchId = string;

const useBranchStore = defineStore('api-branch', () => {
  const flowStore = useFlowStore();
  const data = ref<Pagination<Branch[]>>({
    result: [],
    page: 0,
    pageSize: 0,
    total: 0,
  });
  const map = ref<Record<BranchId, Branch & { contact?: BranchContact[] }>>({});
  const contact: Record<BranchId, BranchContact[]> = {};

  watch(data, () => {
    data.value.result.forEach((v) => {
      map.value[v.id] = v;
    });
  });

  async function fetchList<
    Options extends {
      page?: number;
      pageSize?: number;
      zipCode?: string;
      query?: string;
      tree?: boolean;
      filter?: 'head' | 'sub';
    },
    Data extends Pagination<Branch[]>,
  >(opts?: Options): Promise<Data | false> {
    const params = new URLSearchParams();

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

    const query = params.toString();

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

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

  async function fetchById<
    Options extends { includeSubBranch?: boolean; includeContact?: boolean },
    Data extends Branch &
      (Options['includeSubBranch'] extends true
        ? { branch: Branch[] }
        : unknown) &
      (Options['includeContact'] extends true
        ? { contact: BranchContact[] }
        : unknown),
  >(id: string, opts?: Options): Promise<Data | false> {
    const params = new URLSearchParams();

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

    const query = params.toString();

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

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

    return false;
  }

  async function create(branch: BranchCreate, bank?: BankBook[]) {
    const { qrCodeImage, imageUrl, ...payload } = branch;

    const res = await api.post<
      Branch & {
        qrCodeImageUrl: string;
        qrCodeImageUploadUrl: string;
        imageUploadUrl: string;
      }
    >(
      '/branch',
      { ...payload, bank: bank },
      { headers: { 'X-Rtid': flowStore.rtid } },
    );

    if (qrCodeImage) {
      await api
        .put(`/branch/${res.data.id}/line-image`, qrCodeImage, {
          headers: { 'Content-Type': qrCodeImage.type },
          onUploadProgress: (e) => console.log(e),
        })
        .catch((e) => console.error(e));
    }

    if (imageUrl) {
      await api
        .put(`/branch/${res.data.id}/branch-image`, qrCodeImage, {
          headers: { 'Content-Type': imageUrl.type },
          onUploadProgress: (e) => console.log(e),
        })
        .catch((e) => console.error(e));
    }

    if (!res) return false;

    return res.data;
  }

  async function editById(
    id: string,
    data: Partial<BranchCreate & { status: 'ACTIVE' | 'INACTIVE' | 'CREATED' }>,
    qrCodeImage?: File | undefined,
    imageHq?: File | undefined,
    bank?: BankBook[],
  ) {
    const { ...payload } = data;
    const res = await api.put<
      Branch & { qrCodeImageUploadUrl: string; imageUploadUrl: string }
    >(
      `/branch/${id}`,
      { ...payload, bank: bank },
      {
        headers: { 'X-Rtid': flowStore.rtid },
      },
    );

    if (qrCodeImage) {
      await api
        .put(`/branch/${res.data.id}/line-image`, qrCodeImage, {
          headers: { 'Content-Type': qrCodeImage.type },
          onUploadProgress: (e) => console.log(e),
        })
        .catch((e) => console.error(e));
    }

    if (imageHq) {
      await api
        .put(`/branch/${res.data.id}/branch-image`, imageHq, {
          headers: { 'Content-Type': imageHq.type },
          onUploadProgress: (e) => console.log(e),
        })
        .catch((e) => console.error(e));
    }

    if (!res) return false;

    return res.data;
  }

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

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

    return false;
  }

  async function getUser(branchId: string) {
    const res = await api.get(`/branch/${branchId}/user`, {
      headers: { 'X-Rtid': flowStore.rtid },
    });

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

    return false;
  }

  async function getAdmin(branchId: string | string[]) {
    const res = await api.get<User>(`/branch/${branchId}/admin`, {
      headers: { 'X-Rtid': flowStore.rtid },
    });

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

    return false;
  }

  async function addUser(branchId: string, userId: string | string[]) {
    const res = await api.post(
      `/branch/${branchId}/user`,
      { user: ([] as string[]).concat(userId) },
      { headers: { 'X-Rtid': flowStore.rtid } },
    );

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

    return false;
  }

  async function removeUser(branchId: string, userId: string | string[]) {
    const res = await api.delete(`/branch/${branchId}/user`, {
      headers: { 'X-Rtid': flowStore.rtid },
      data: { user: ([] as string[]).concat(userId) },
    });

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

    return false;
  }

  async function stats() {
    const res = await api.get<{
      hq: number;
      br: number;
    }>('/branch/stats', {
      headers: {
        'X-Rtid': flowStore.rtid,
      },
    });

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

    return false;
  }

  async function userStats(userType: string) {
    const res = await api.get(
      `/branch/user-stats${userType ? '?'.concat(userType) : ''}`,
      {
        headers: { 'X-Rtid': flowStore.rtid },
      },
    );

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

    return false;
  }

  async function getContact(branchId: BranchId, force = false) {
    if (!force && contact[branchId]) return contact[branchId];

    const res = await fetchById(branchId, { includeContact: true });

    if (res) {
      contact[branchId] = res.contact;
      return res.contact;
    }

    return false;
  }

  return {
    data,
    map,
    fetchList,
    fetchById,

    create,
    editById,
    deleteById,

    getAdmin,
    getUser,
    addUser,
    removeUser,

    getContact,

    stats,
    userStats,
  };
});

export default useBranchStore;
