import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';

import {
  decryptAssymmetric,
  encryptAssymmetric
} from '@app/components/utilities/cryptography/crypto';
import { apiRequest } from '@app/config/request';
import { setAuthToken } from '@app/reactQuery';

import { useUploadWsKey } from '../keys/queries';
import {
  AddUserToOrgDTO,
  AddUserToWsDTO,
  AddUserToWsRes,
  DeletOrgMembershipDTO,
  OrgUser,
  UpdateOrgUserRoleDTO,
  User
} from './types';

const userKeys = {
  getUser: ['user'] as const,
  userAction: ['user-action'] as const,
  getOrgUsers: (orgId: string) => [{ orgId }, 'user']
};

const fetchUserDetails = async () => {
  const { data } = await apiRequest.get<{ user: User }>('/api/v1/user');

  return data.user;
};

export const useGetUser = () => useQuery(userKeys.getUser, fetchUserDetails);

const fetchUserAction = async (action: string) => {
  const { data } = await apiRequest.get<{ userAction: string }>('/api/v1/user-action', {
    params: {
      action
    }
  });
  return data.userAction;
};

export const useGetUserAction = (action: string) =>
  useQuery({
    queryKey: userKeys.userAction,
    queryFn: () => fetchUserAction(action)
  });

export const fetchOrgUsers = async (orgId: string) => {
  const { data } = await apiRequest.get<{ users: OrgUser[] }>(
    `/api/v1/organization/${orgId}/users`
  );

  return data.users;
};

export const useGetOrgUsers = (orgId: string) =>
  useQuery({
    queryKey: userKeys.getOrgUsers(orgId),
    queryFn: () => fetchOrgUsers(orgId),
    enabled: Boolean(orgId)
  });

// mutation
export const useAddUserToWs = () => {
  const uploadWsKey = useUploadWsKey();

  return useMutation<{ data: AddUserToWsRes }, {}, AddUserToWsDTO>({
    mutationFn: ({ email, workspaceId }) =>
      apiRequest.post(`/api/v1/workspace/${workspaceId}/invite-signup`, { email }),
    onSuccess: ({ data }, { workspaceId }) => {
      const PRIVATE_KEY = localStorage.getItem('PRIVATE_KEY');
      if (!PRIVATE_KEY) return;

      // assymmetrically decrypt symmetric key with local private key
      const key = decryptAssymmetric({
        ciphertext: data.latestKey.encryptedKey,
        nonce: data.latestKey.nonce,
        publicKey: data.latestKey.sender.publicKey,
        privateKey: PRIVATE_KEY
      });

      const { ciphertext: inviteeCipherText, nonce: inviteeNonce } = encryptAssymmetric({
        plaintext: key,
        publicKey: data.invitee.publicKey,
        privateKey: PRIVATE_KEY
      });

      uploadWsKey.mutate({
        encryptedKey: inviteeCipherText,
        nonce: inviteeNonce,
        userId: data.invitee._id,
        workspaceId
      });
    }
  });
};

export const useAddUserToOrg = () => {
  const queryClient = useQueryClient();
  type Response  = {
    data: {
      message: string, 
      completeInviteLink: string | undefined
    }
  }

  return useMutation<Response, {}, AddUserToOrgDTO>({
    mutationFn: (dto) => apiRequest.post(`/api/v1/invite-org/signup`, dto),
    onSuccess: (_, { organizationId }) => {
      queryClient.invalidateQueries(userKeys.getOrgUsers(organizationId));
    }
  });
};

export const useDeleteOrgMembership = () => {
  const queryClient = useQueryClient();

  return useMutation<{}, {}, DeletOrgMembershipDTO>({
    mutationFn: ({ membershipId, orgId }) =>
      apiRequest.delete(`/api/v2/organizations/${orgId}/memberships/${membershipId}`),
    onSuccess: (_, { orgId }) => {
      queryClient.invalidateQueries(userKeys.getOrgUsers(orgId));
    }
  });
};

export const useUpdateOrgUserRole = () => {
  const queryClient = useQueryClient();

  return useMutation<{}, {}, UpdateOrgUserRoleDTO>({
    mutationFn: ({ organizationId, membershipId, role }) =>
      apiRequest.patch(`/api/v2/organizations/${organizationId}/memberships/${membershipId}`, {
        role
      }),
    onSuccess: (_, { organizationId }) => {
      queryClient.invalidateQueries(userKeys.getOrgUsers(organizationId));
    },
    // to remove old states
    onError: (_, { organizationId }) => {
      queryClient.invalidateQueries(userKeys.getOrgUsers(organizationId));
    }
  });
};

export const useRegisterUserAction = () => {
  const queryClient = useQueryClient();
  return useMutation<{}, {}, string>({
    mutationFn: (action) => apiRequest.post('/api/v1/user-action', { action }),
    onSuccess: () => {
      queryClient.invalidateQueries(userKeys.userAction);
    }
  });
};

export const useLogoutUser = () =>
  useMutation({
    mutationFn: () => apiRequest.post('/api/v1/auth/logout'),
    onSuccess: () => {
      setAuthToken('');
      // Delete the cookie by not setting a value; Alternatively clear the local storage
      localStorage.setItem('publicKey', '');
      localStorage.setItem('encryptedPrivateKey', '');
      localStorage.setItem('iv', '');
      localStorage.setItem('tag', '');
      localStorage.setItem('PRIVATE_KEY', '');
    }
  });
