import axios from "axios";

export type LoginErrorType =
  | "validation"
  | "auth"
  | "forbidden"
  | "rate_limit"
  | "server"
  | "network";

export type LoginFieldErrors = {
  email?: string;
  password?: string;
};

export class AdminLoginError extends Error {
  readonly type: LoginErrorType;
  readonly fieldErrors: LoginFieldErrors;

  constructor(message: string, type: LoginErrorType, fieldErrors: LoginFieldErrors = {}) {
    super(message);
    this.name = "AdminLoginError";
    this.type = type;
    this.fieldErrors = fieldErrors;
  }
}

type ApiErrorPayload = {
  message?: string;
  error?: string;
  errors?: Record<string, string[]>;
};

function mapFieldErrors(errors?: Record<string, string[]>): LoginFieldErrors {
  const fieldErrors: LoginFieldErrors = {};

  if (!errors) {
    return fieldErrors;
  }

  for (const [field, messages] of Object.entries(errors)) {
    if (field === "email" || field === "password") {
      const message = messages?.[0];
      if (message) {
        fieldErrors[field] = message;
      }
    }
  }

  return fieldErrors;
}

export function parseAdminLoginError(error: unknown): AdminLoginError {
  if (!axios.isAxiosError(error)) {
    return new AdminLoginError(
      "Unable to reach the server. Check your connection and try again.",
      "network"
    );
  }

  if (!error.response) {
    return new AdminLoginError(
      "Unable to reach the server. Check your connection and try again.",
      "network"
    );
  }

  const status = error.response.status;
  const data = error.response.data as ApiErrorPayload | undefined;
  const fieldErrors = mapFieldErrors(data?.errors);

  switch (status) {
    case 422:
      return new AdminLoginError(
        data?.message || "Please correct the errors below.",
        "validation",
        fieldErrors
      );
    case 401:
      return new AdminLoginError(
        data?.message || "Invalid email or password.",
        "auth"
      );
    case 403:
      return new AdminLoginError(
        data?.message || "You are not authorized to access the admin panel.",
        "forbidden"
      );
    case 429:
      return new AdminLoginError(
        data?.message || "Too many login attempts. Please try again later.",
        "rate_limit"
      );
    default:
      if (status >= 500) {
        return new AdminLoginError(
          data?.message || "Something went wrong on our end. Please try again later.",
          "server"
        );
      }

      return new AdminLoginError(
        data?.message || "Sign in failed. Please try again.",
        "auth"
      );
  }
}

export function isAdminLoginError(error: unknown): error is AdminLoginError {
  return error instanceof AdminLoginError;
}
