import { error } from '@sveltejs/kit';
import type { ItemCount, TodoItem, User } from './types';
import { getResponseBodyOrError } from '$lib/api/utils';
import { getTokenFromLocalstorage } from '$lib/auth/session';

/**
  * Retrieves the currently logged in user's JWT from localstorage,
  * or throws an error if it is not present.
  *
  * @throws {error} - If the current user is not logged in or if their JWT is not saved in localstorage.
  */
function getTokenOrError(): string {
  let token = getTokenFromLocalstorage();
  if (token === null) {
    throw error(401, 'You are not logged in.');
  }
  return token;
}

/**
 * Retrieves the user with the specified ID from the backend API.
 *
 * @param {number} userId - The ID of the user whom to retrieve.
 * @param {string} jwt - The JWT appended as a bearer token to authorize the request.
 * @throws{error} - If the request fails or is not permitted.
 */
export async function readUser(userId: number, jwt: string = getTokenOrError()): Promise<User> {
  const endpoint = `/api/users/${userId}`;
  const response = await fetch(endpoint, {
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Authorization': `Bearer ${jwt}`,
      'Content-Type': 'application/json',
    }
  });

  const responseJson = await getResponseBodyOrError(response);
  return responseJson as User;
}

/**
 * Retrieves the list of all users from the backend API.
 *
 * @param {string} jwt - The JWT appended as a bearer token to authorize the request.
 * @throws{error} - If the request fails or is not permitted.
 */
export async function readUsers(
  skip: number,
  limit: number,
  sortby: string,
  sortorder: string,
  jwt: string = getTokenOrError(),
): Promise<User[]> {

  const urlParameters = new URLSearchParams({
    skip: `${skip}`,
    limit: `${limit}`,
    sortby: `${sortby}`,
    sortorder: `${sortorder}`,
  });
  const endpoint = `/api/admin/users/?${urlParameters}`;

  const response = await fetch(endpoint, {
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Authorization': `Bearer ${jwt}`,
      'Content-Type': 'application/json',
    }
  });

  const responseJson = await getResponseBodyOrError(response);
  return responseJson as User[];
}

/**
 * Retrieves the total user count from the backend API.
 *
 * @param {string} jwt - The JWT appended as a bearer token to authorize the request.
 * @throws{error} - If the request fails or is not permitted.
 */
export async function readUserCount(jwt: string = getTokenOrError()): Promise<number> {
  const endpoint = '/api/admin/users/total/';
  const response = await fetch(endpoint, {
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Authorization': `Bearer ${jwt}`,
      'Content-Type': 'application/json',
    }
  });

  const responseJson = await getResponseBodyOrError(response);
  const itemCount = responseJson as ItemCount;
  return itemCount.total;
}

/**
 * Retrieves the list of all todo-items for the user with the specified ID from the backend API.
 *
 * @param {string} jwt - The JWT appended as a bearer token to authorize the request.
 * @throws{error} - If the request fails or is not permitted.
 */
export async function readTodos(
  userId: number,
  skip: number,
  limit: number,
  sortby: string,
  sortorder: string,
  jwt: string = getTokenOrError(),
): Promise<TodoItem[]> {

  const urlParameters = new URLSearchParams({
    skip: `${skip}`,
    limit: `${limit}`,
    sortby: `${sortby}`,
    sortorder: `${sortorder}`,
  });
  const endpoint = `/api/todos/user/${userId}?${urlParameters}`;

  const response = await fetch(endpoint, {
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Authorization': `Bearer ${jwt}`,
      'Content-Type': 'application/json',
    }
  });

  const responseJson = await getResponseBodyOrError(response);
  return responseJson as TodoItem[];
}

/**
 * Retrieves the total todo-item count for the user with the specified ID from the backend API.
 *
 * @param {string} jwt - The JWT appended as a bearer token to authorize the request.
 * @throws{error} - If the request fails or is not permitted.
 */
export async function readTodoCount(
  userId: number,
  jwt: string = getTokenOrError()
): Promise<number> {
  const endpoint = `/api/todos/user/${userId}/total/`;
  const response = await fetch(endpoint, {
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Authorization': `Bearer ${jwt}`,
      'Content-Type': 'application/json',
    }
  });

  const responseJson = await getResponseBodyOrError(response);
  const itemCount = responseJson as ItemCount;
  return itemCount.total;
}

/**
 * Retrieves the todo-item with the specified ID from the backend API.
 *
 * @param {string} jwt - The JWT appended as a bearer token to authorize the request.
 * @throws{error} - If the request fails or is not permitted.
 */
export async function readTodo(
  todoId: number,
  jwt: string = getTokenOrError()
): Promise<TodoItem> {
  const endpoint = `/api/todos/${todoId}`;
  const response = await fetch(endpoint, {
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'Authorization': `Bearer ${jwt}`,
      'Content-Type': 'application/json',
    }
  });

  const responseJson = await getResponseBodyOrError(response);
  return responseJson as TodoItem;
}
