package com.njzscloud.common.core.utils;

import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.njzscloud.common.core.ex.ExceptionMsg;
import com.njzscloud.common.core.ex.Exceptions;
import com.njzscloud.common.core.jackson.Jackson;
import lombok.Getter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;

/**
 * 响应信息主体
 *
 * @param <T>
 */
@Getter
@SuppressWarnings("unchecked")
public final class R<T> {
    /**
     * <p>错误码 >= 0</p>
     * <p>0 --> 没有错误</p>
     * <p>其他 --> 有错误</p>
     */
    private final int code;
    /**
     * 是否成功
     */
    private final boolean success;

    /**
     * 简略信息
     */
    private final String msg;
    /**
     * 响应数据
     */
    private T data;
    /**
     * 详细信息
     */
    private Object message;

    private R(T data, ExceptionMsg msg, Object message) {
        this(msg.code, data, msg.msg, message);
    }

    @JsonCreator
    private R(@JsonProperty("code") int code,
              @JsonProperty("data") T data,
              @JsonProperty("msg") String msg,
              @JsonProperty("message") Object message) {
        this.data = data;
        this.code = code;
        this.msg = msg;
        this.message = message;
        this.success = code == 0;
    }

    /**
     * 成功，响应码：0，响应信息：成功，详细信息：null，响应数据：null
     *
     * @param <D> 响应数据的类型
     * @return R&lt;D&gt;
     */
    public static <D> R<D> success() {
        return new R<>(0, null, "成功", null);
    }

    /**
     * 成功，响应码：0，响应信息：成功，详细信息：null
     *
     * @param data 响应数据
     * @param <D>  响应数据的类型
     * @return R&lt;D&gt;
     */
    public static <D> R<D> success(D data) {
        return new R<>(0, data, "成功", null);
    }

    /**
     * 成功，响应码：0，详细信息：null
     *
     * @param data 响应数据
     * @param msg  响应信息
     * @param <D>  响应数据的类型
     * @return R&lt;D&gt;
     */
    public static <D> R<D> success(D data, String msg) {
        return new R<>(0, data, msg, null);
    }

    /**
     * 失败，响应码：11111，响应信息：系统异常！，详细信息：null，响应数据：null
     *
     * @param <D> 响应数据的类型
     * @return R&lt;D&gt;
     */
    public static <D> R<D> failed() {
        return new R<>(null, ExceptionMsg.SYS_EXP_MSG, null);
    }

    /**
     * 失败，详细信息：null，响应数据：null
     *
     * @param msg 简略错误信息
     * @param <D> 响应数据的类型
     * @return R&lt;D&gt;
     * @see ExceptionMsg
     */
    public static <D> R<D> failed(ExceptionMsg msg) {
        return new R<>(null, msg, null);
    }

    public static <D> R<D> failed(ExceptionMsg msg, Object message) {
        return new R<>(null, msg, message);
    }

    public static <D> R<D> failed(ExceptionMsg msg, String message, Object... param) {
        if (StrUtil.isNotBlank(message) && param != null && param.length > 0) {
            message = StrUtil.format(message, param);
        }
        return new R<>(null, msg, message);
    }

    /**
     * 失败，详细信息：null
     *
     * @param data 响应数据
     * @param msg  简略错误信息
     * @param <D>  响应数据的类型
     * @return R&lt;D&gt;
     * @see ExceptionMsg
     */
    public static <D> R<D> failed(D data, ExceptionMsg msg) {
        return new R<>(null, msg, null);
    }

    public static <D> R<D> failed(D data, ExceptionMsg msg, Object message) {
        return new R<>(null, msg, message);
    }

    /**
     * 设置响应数据
     *
     * @param data 响应数据
     * @return R&lt;D&gt;
     */
    public R<T> setData(T data) {
        this.data = data;
        return this;
    }

    /**
     * <p>添加响应数据</p>
     * <p>需确保 data 为 Map 类型且 Key 为 String，data 为 null 时，会新建</p>
     *
     * @param key 键
     * @param val 值
     * @return R&lt;T&gt;
     */
    public <V> R<Map<String, V>> put(String key, V val) {
        if (this.data == null) {
            R<Map<String, V>> r = new R<>(this.code, new HashMap<>(), this.msg, this.message);
            r.data.put(key, val);
            return r;
        } else if (Map.class.isAssignableFrom(data.getClass())) {
            ((Map<String, V>) this.data).put(key, val);
            return (R<Map<String, V>>) this;
        }

        throw Exceptions.error("响应信息构建失败");
    }

    /**
     * <p>添加响应数据</p>
     * <p>需确保 data 为 List 类型，data 为 null 时，会新建</p>
     *
     * @param val 值
     * @return R&lt;T&gt;
     */
    public <V> R<List<V>> add(V val) {
        if (this.data == null) {
            R<List<V>> r = new R<>(this.code, new ArrayList<>(), this.msg, this.message);
            r.data.add(val);
            return r;
        } else if (List.class.isAssignableFrom(data.getClass())) {
            ((List<V>) this.data).add(val);
            return (R<List<V>>) this;
        }
        throw Exceptions.error("响应信息构建失败");
    }

    /**
     * 设置详细信息
     *
     * @param message 详细信息
     * @return R&lt;T&gt;
     */
    public R<T> setMessage(Object message) {
        this.message = message;
        return this;
    }

    /**
     * 设置详细信息
     *
     * @param message 消息字符串模板，占位符：{}
     * @param param   占位符参数
     * @return R&lt;T&gt;
     */
    public R<T> setMessage(String message, Object... param) {
        if (StrUtil.isNotBlank(message) && param != null && param.length > 0) {
            message = StrUtil.format(message, param);
        }
        this.message = message;
        return this;
    }

    /**
     * <p>转换</p>
     * <p>将响应数据转换为其他对象</p>
     * <p>code、msg、message 不变化</p>
     *
     * @param converter 转换器
     * @param <D>       新响应数据的类型
     * @return R&lt;D&gt;
     */
    public <D> R<D> convert(Function<T, D> converter) {
        D d = converter.apply(this.data);
        return new R<>(this.code, d, this.msg, this.message);
    }

    @Override
    public String toString() {
        return Jackson.toJsonStr(this);
    }
}
