import isEmpty from 'lodash/isEmpty';
import { AuthProvider, OnErrorResponse } from "@refinedev/core";
import { IUser } from "../interfaces";

const API_URL = "/api/v1";
const LOCAL_STORAGE_USER_KEY = "rpk-gui-current-user";
const GOOGLE_SCOPES = { "scopes": "https://www.googleapis.com/auth/userinfo.profile https://www.googleapis.com/auth/userinfo.email" };
const DISCORD_SCOPES = { "scopes": "identify email" }

const DEFAULT_LOGIN_REDIRECT = "/hub"

const authProvider: AuthProvider = {
  login: async ({ providerName, email, password }) => {
    const to_param = findGetParameter("to");
    const redirect = to_param === null ? getLoginRedirect() : to_param
    if (providerName) {
      let scope = {};
      if (providerName === "google") {
        scope = GOOGLE_SCOPES;
      } else if (providerName === "discord") {
        scope = DISCORD_SCOPES;
      }
      const params = new URLSearchParams(scope);
      const url = `${API_URL}/hub/auth/${providerName}/authorize?${params.toString()}`;
      const response = await fetch(url, { method: "GET", },);
      const body = await response.json();


      localStorage.setItem("redirect_after_login", redirect);

      window.location.href = body.authorization_url;
      return {
        success: true,
        redirectTo: ""
      };
    } else if (email !== undefined && password !== undefined) {
      const params = new URLSearchParams({"grant_type": "password", "username": email, "password": password});
      const response = await fetch(
        `${API_URL}/hub/auth/login`,
        {
          method: "POST",
          body: params.toString(),
          headers: { "Content-Type": "application/x-www-form-urlencoded", },
        },
      );
      if (response.status >= 200 && response.status < 300) {
        const response = await fetch(`${API_URL}/hub/users/me`);
        const user = await response.json();
        store_user(user);

        return {
          success: true,
          redirectTo: redirect,
        };
      }
    }

    return { success: false };
  },
  logout: async () => {
    const response = await fetch(`${API_URL}/hub/auth/logout`, { method: "POST" });
    if (response.status == 204 || response.status == 401) {
      forget_user();
      return { success: true };
    }
    return { success: false };
  },
  check: async () => {
    const user = get_user();
    if (user == null || isEmpty(user)) {
      const user_data = await get_me();

      if (user_data) {
        store_user(user_data)
        return { authenticated: true }
      }

      return {
        authenticated: false,
        logout: true
      }
    }
    return { authenticated: true };
  },
  getIdentity: async (): Promise<IUser> => {
    const user = get_user();
    if (user !== null && !isEmpty(user)) {
      return user;
    }

    const user_data = get_me()
    store_user(user_data)

    return user_data;
  },
  register: async (params) => {
    const response = await fetch(`${API_URL}/hub/register`, {
      method: "POST",
      body: JSON.stringify(params),
      headers: {
        "Content-Type": "application/json",
      },
    });

    if (response.status == 201) {
      return { success: true, redirectTo: "/", };
    }

    return {
      success: false,
      error: {
        message: "Register failed",
        name: "Invalid email or password",
      },
    };
  },
  forgotPassword: async (params) => {
    const response = await fetch(`${API_URL}/hub/users/forgot-password`, {
      method: "POST",
      body: JSON.stringify(params),
      headers: {
        "Content-Type": "application/json",
      },
    });

    if (response.status == 202) {
      return { success: true, redirectTo: "/", };
    }

    return { success: false, };
  },
  updatePassword: async (params) => {
    if (params.token !== undefined) {
      const response = await fetch(`${API_URL}/hub/users/reset-password`, {
        method: "POST",
        body: JSON.stringify({
          password: params.password,
          token: params.token,
        }),
        headers: {
          "Content-Type": "application/json",
        },
      });

      if (response.status == 200) {
        return { success: true, redirectTo: "/", };
      }
    }

    return { success: false, };
  },
  getPermissions: async () => { throw new Error("Not implemented"); },
  onError: async (error) => {
    if (error?.status === 401) {
      forget_user();
      return {
        error: { message: "Authentication required" },
        logout: true,
      } as OnErrorResponse;
    }
    else if (error?.status === 403) {
      return {
        error: { message: "Insufficient credentials" },
      } as OnErrorResponse;
    }
    return {
        error: { message: "Unexpected authentication error" },
    } as OnErrorResponse;
  },
};

async function get_me() {
  const response = await fetch(`${API_URL}/hub/users/me`);
  if (response.status < 200 || response.status > 299) {
    return null;
  }
  const user_data = await response.json();
  return user_data
}

function store_user(user: any) {
  localStorage.setItem(LOCAL_STORAGE_USER_KEY, JSON.stringify(user));
}

function get_user() {
  const user_string = localStorage.getItem(LOCAL_STORAGE_USER_KEY)
  if (user_string == null) {
    return null
  }
  return JSON.parse(user_string);
}

function forget_user() {
  localStorage.removeItem(LOCAL_STORAGE_USER_KEY);
}

export function empty_user() {
  store_user({})
}

function findGetParameter(parameterName: string) {
    let result = null, tmp = [];
    location.search.substring(1).split("&")
        .forEach(function (item) {
          tmp = item.split("=");
          if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
        });
    return result;
}

function getLoginRedirect() {
  if (location.pathname == "/login") {
    return DEFAULT_LOGIN_REDIRECT
  }

  return location.pathname + location.search;
}
export default authProvider;
