package com.hdkj.fhzg.entity;

import lombok.*;
import lombok.experimental.Accessors;
import org.springframework.lang.Nullable;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * @author zhangfan
 * @date 2021/9/15/0015
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@Accessors(chain = true)
@EqualsAndHashCode
public class ResultModel<T> implements Serializable {
    private static final long serialVersionUID = -4544427215199386509L;
    private Integer code;
    private String msg;
    private T data;

    public static <T> ResultModel<T> ok(ResultEnum result, T data) {
        return result(result, data);
    }

    public static <T> ResultModel<T> ok(ResultEnum result) {
        return result(result, null);
    }
    
    public static <T> ResultModel<T> ok(T data) {
        return result(ResultEnum.SUCCESS, data);
    }

    public static <T> ResultModel<T> ok(String msg) {
        return custom(ResultEnum.SUCCESS.getCode(), msg);
    }

    public static <T> ResultModel<T> error(ResultEnum result, T data) {
        return result(result, data);
    }


    public static <T> ResultModel<T> error(String msg) {
        return custom(ResultEnum.FAILED.getCode(), msg);
    }

    public static <T> ResultModel<T> error(ResultEnum result) {
        return result(result, null);
    }

    public static <T> ResultModel<T> result(ResultEnum result, T data) {
        ResultModel<T> resultModel = new ResultModel<>();
        resultModel.setCode(result.getCode()).setMsg(result.getMsg());
        if (data != null) {
            resultModel.setData(data);
        }
        return resultModel;
    }

    public static <T> ResultModel<T> custom(Integer code, String msg, T data) {
        return new ResultModel<>(code, msg, data);
    }

    public static <T> ResultModel<T> custom(Integer code, String msg) {
        return new ResultModel<>(code, msg, null);
    }


    public static boolean isSuccess(@Nullable ResultModel<?> result) {
        return (Boolean) Optional.ofNullable(result).map((x) -> {
            return ObjectUtils.nullSafeEquals(ResultEnum.SUCCESS.getCode(), x.code);
        }).orElse(Boolean.FALSE);
    }

    public <E extends Throwable> T orElseThrow(Supplier<E> supplier) throws E{
        if(!Objects.equals(getCode(), ResultEnum.SUCCESS.getCode()) || data == null){
            throw supplier.get();
        }
        return data;
    }

    public <E extends Throwable> T orElseThrow(Function<ResultModel<T>,E> function) throws E{
        if(!Objects.equals(getCode(), ResultEnum.SUCCESS.getCode())){
            throw function.apply(this);
        }
        return data;
    }

    public static <T> ResultModel<T> ApiOk(T data) {
        return result(ResultEnum.OK, data);
    }
}
