import {
  NewWeeklyReport,
  NewUser,
  User,
  Project,
  NewProject,
} from "../Types/goTypes";

// This type of pattern should be hard to misuse
export interface APIResponse<T> {
  success: boolean;
  message?: string;
  data?: T;
}

// Note that all protected routes also require a token
// Defines all the methods that an instance of the API must implement
interface API {
  /** Register a new user */
  registerUser(user: NewUser): Promise<APIResponse<User>>;
  /** Remove a user */
  removeUser(username: string, token: string): Promise<APIResponse<User>>;
  /** Create a project */
  createProject(
    project: NewProject,
    token: string,
  ): Promise<APIResponse<Project>>;
  /** Submit a weekly report */
  submitWeeklyReport(
    project: NewWeeklyReport,
    token: string,
  ): Promise<APIResponse<Project>>;
  /** Renew the token */
  renewToken(token: string): Promise<APIResponse<string>>;
  /** Gets all the projects of a user*/
  getUserProjects(
    username: string,
    token: string,
  ): Promise<APIResponse<Project[]>>;
  /** Login */
  login(NewUser: NewUser): Promise<APIResponse<string>>;
}

// Export an instance of the API
export const api: API = {
  async registerUser(user: NewUser): Promise<APIResponse<User>> {
    try {
      const response = await fetch("/api/register", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(user),
      });

      if (!response.ok) {
        return { success: false, message: "Failed to register user" };
      } else {
        const data = (await response.json()) as User;
        return { success: true, data };
      }
    } catch (e) {
      return { success: false, message: "Failed to register user" };
    }
  },

  async removeUser(
    username: string,
    token: string,
  ): Promise<APIResponse<User>> {
    try {
      const response = await fetch("/api/userdelete", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer " + token,
        },
        body: JSON.stringify(username),
      });

      if (!response.ok) {
        return { success: false, message: "Failed to remove user" };
      } else {
        const data = (await response.json()) as User;
        return { success: true, data };
      }
    } catch (e) {
      return { success: false, message: "Failed to remove user" };
    }
  },

  async createProject(
    project: NewProject,
    token: string,
  ): Promise<APIResponse<Project>> {
    try {
      const response = await fetch("/api/project", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer " + token,
        },
        body: JSON.stringify(project),
      });

      if (!response.ok) {
        return { success: false, message: "Failed to create project" };
      } else {
        const data = (await response.json()) as Project;
        return { success: true, data };
      }
    } catch (e) {
      return { success: false, message: "Failed to create project" };
    }
  },

  async renewToken(token: string): Promise<APIResponse<string>> {
    try {
      const response = await fetch("/api/loginrenew", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer " + token,
        },
      });

      if (!response.ok) {
        return { success: false, message: "Failed to renew token" };
      } else {
        const data = (await response.json()) as string;
        return { success: true, data };
      }
    } catch (e) {
      return { success: false, message: "Failed to renew token" };
    }
  },

  async getUserProjects(token: string): Promise<APIResponse<Project[]>> {
    try {
      const response = await fetch("/api/getUserProjects", {
        method: "GET",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer " + token,
        },
      });

      if (!response.ok) {
        return Promise.resolve({
          success: false,
          message: "Failed to get user projects",
        });
      } else {
        const data = (await response.json()) as Project[];
        return Promise.resolve({ success: true, data });
      }
    } catch (e) {
      return Promise.resolve({
        success: false,
        message: "Failed to get user projects",
      });
    }
  },

  async submitWeeklyReport(
    project: NewWeeklyReport,
    token: string,
  ): Promise<APIResponse<Project>> {
    try {
      return fetch("/api/submitWeeklyReport", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: "Bearer " + token,
        },
        body: JSON.stringify(project),
      })
        .then((response) => {
          if (!response.ok) {
            return {
              success: false,
              message: "Failed to submit weekly report",
            };
          } else {
            return response.json();
          }
        })
        .then((data: Project) => {
          return { success: true, data };
        });
    } catch (e) {
      return Promise.resolve({
        success: false,
        message: "Failed to submit weekly report",
      });
    }
  },

  async login(NewUser: NewUser): Promise<APIResponse<string>> {
    try {
      const response = await fetch("/api/login", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
        },
        body: JSON.stringify(NewUser),
      });

      if (!response.ok) {
        return { success: false, message: "Failed to login" };
      } else {
        const data = (await response.json()) as { token: string }; // Update the type of 'data'
        return { success: true, data: data.token };
      }
    } catch (e) {
      return Promise.resolve({ success: false, message: "Failed to login" });
    }
  },
};
