import AsyncStorage from "@react-native-async-storage/async-storage";
import { router } from "expo-router";
import { getItemAsync } from "expo-secure-store";
import apiClient from "../client";
import { AUTH } from "../endpoints";

export abstract class AbstractService {
  protected IDP_URL =
    "https://codefirst.iut.uca.fr/containers/Optifit-optifit-ef-api/api/v1";
  protected URL =
    "https://codefirst.iut.uca.fr/containers/Optifit-optifit-ef-api/api/v1";

  protected CLIENT_ID = "mobile-app";
  protected CLIENT_SECRET = "super-secret";

  protected SCOPES =
    "openid profile training.generate training.read offline_access";

  protected ACCESS_TOKEN_PATH = "access-token";
  protected REFRESH_TOKEN_PATH = "refresh-token";

  protected async request(
    path: string,
    options: RequestInit = {}
  ): Promise<any> {
    const token = await getItemAsync(this.ACCESS_TOKEN_PATH);
    const res = await fetch(`${this.URL}${path}`, {
      ...options,
      headers: {
        ...(options.headers || {}),
        Authorization: `Bearer ${token}`,
      },
    });

    switch (res.status) {
      case 401:
        await this.tryRefreshToken();
        return this.request(path, options);
      case 403:
        router.replace("/(error)/NotAllowedProblem");
        return;
      case 500:
        router.replace("/(error)/InternalErrorProblem");
        return;
      case 503:
        router.replace("/(error)/BlockedProblem");
        return;
      default:
        return await res.json();
    }
  }

  private async tryRefreshToken(): Promise<boolean> {
    try {
      const refreshToken = await AsyncStorage.getItem(this.REFRESH_TOKEN_PATH);

      if (!refreshToken) return false;

      const response = await apiClient.post(AUTH.REFRESH_TOKEN, {
        refreshToken,
      });

      const { accessToken, refreshToken: newRefreshToken } = response.data;

      await AsyncStorage.setItem(this.ACCESS_TOKEN_PATH, accessToken);
      await AsyncStorage.setItem(this.REFRESH_TOKEN_PATH, newRefreshToken);

      apiClient.defaults.headers.common[
        "Authorization"
      ] = `Bearer ${accessToken}`;

      return true;
    } catch (e) {
      return false;
    }
  }
}
