import { AxiosError } from "axios";
import _ from "lodash";
import { DTOModel } from "./dto_model";


export interface FailureI {
  status?: number;
  message: string;
  key?: string;
  meta?: FailureMeta;
}

interface FailureMeta {
  isRequestFailure?: boolean;
  isNetworkFailure?: boolean;
  isPlainFailure?: boolean;
  data?: any;
  [prop: string]: any | undefined;
}

class Failure implements FailureI {
  message: string;
  key?: string | undefined;
  status?: number | undefined;
  meta?: FailureMeta;
  static isf = true;

  /**
   * 
   * @param {Failure} o
   * @returns {boolean}
   */
  static isFailure(o: any): o is Failure {
    if(!_.isObjectLike(o)) return false;
    if(_.has(o, 'message')) return true;
    return false;
  };
  
  

  constructor({ status, message, key, meta }: FailureI) {
    this.status = status;
    this.message = message;
    this.key = key;
    this.meta = meta;
    console.error([key ?? '', message].filter((i) => i.length !== 0).join(':'));
  }

  static fromReason(reason: AxiosError<DTOModel<any>>, key?: string): Failure {
    if (reason.response) {
      return new Failure({
        status: reason.response!.status,
        message:
          reason.response!.data.message ?? "Unknown response error model",
        key: key,
        meta: {
          isRequestFailure: true,
          data: reason.response.data,
        },
      });
    }
    if (reason.request) {
      return new Failure({
        message: `Something went wrong while ${reason.config.url} had been called`,
        key: `unreachedResponse(${key})`,
        meta: {
          isNetworkFailure: true,
        },
      });
    }
    return new Failure({
      message: reason.message,
      key: key,
      meta: { isPlainFailure: true },
    });
  }

  toString(): string {
    return `${this.message} (${this.key ?? "key unknown"}) ${
      this.status ?? "status unknown"
    }`;
  }

  mapKeyWith(transpiler: (key: string) => string) {
    if (!this.key) {
      return this.message;
    }
    return transpiler(this.key);
  }
}

export default Failure;
