/*
 * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
 *
 * https://www.mall4j.com/
 *
 * 未经允许，不可做商业用途！
 *
 * 版权所有，侵权必究！
 */

// 该类所属的包名，表明其位于商城项目的通用（common）响应（response）包下，主要用于封装服务器端向客户端返回的响应信息，统一响应格式，方便客户端解析和处理，
// 同时提供了多种静态方法来便捷地创建不同状态（成功、失败等）的响应实体对象，以满足不同业务场景下的需求。
package com.yami.shop.common.response;

import lombok.extern.slf4j.Slf4j;
import java.io.Serializable;
import java.util.Objects;

/**
 * ServerResponseEntity类是一个泛型类，用于构建服务器端向客户端返回的统一响应实体，它封装了响应的关键信息，如状态码、提示消息、具体数据内容、版本号以及时间戳等，
 * 并且通过一系列静态方法可以方便地创建各种不同情况（成功、失败以及带特定数据的不同状态等）下的响应实体实例，同时还提供了判断响应是否成功或失败的方法，有助于在业务逻辑中对响应结果进行统一处理。
 *
 * @author lanhai
 */
@Slf4j
// 使用@Slf4j注解，会自动为该类生成一个名为log的日志记录器，方便在类的各个方法中记录日志信息，例如在创建失败响应时记录错误相关的日志等操作，便于后续排查问题和了解程序执行情况。
public class ServerResponseEntity<T> implements Serializable {

    /**
     * 状态码，用于标识响应的状态，不同的业务场景或者不同的结果情况会对应不同的状态码，客户端可以根据状态码来判断请求是否成功以及具体的业务处理结果类型，例如常见的200表示成功等，
     * 这里的状态码具体格式和含义由项目内部自行定义（可能参照了一些通用的HTTP状态码概念并结合自身业务做了扩展）。
     */
    private String code;

    /**
     * 信息，用于向客户端传递一些提示性的消息内容，比如在成功时可以是操作成功的简要说明，在失败时则是具体的错误原因描述，方便客户端展示给用户或者进行相应的业务逻辑处理。
     */
    private String msg;

    /**
     * 数据，是泛型类型的成员变量，用于承载具体的业务数据内容，根据不同的接口请求和业务逻辑，这个数据部分可以是各种类型的对象，例如查询商品信息接口返回的商品对象列表、用户信息接口返回的用户对象等。
     */
    private T data;

    /**
     * 版本，用于标识当前响应实体对应的版本信息，可能在项目进行版本迭代、接口升级等情况下，通过这个版本号来区分不同版本的响应格式或者数据结构等变化，这里固定初始化为"mall4j.v230424"，具体含义和使用场景由项目决定。
     */
    private String version;

    /**
     * 时间戳，通常用于记录响应生成的时间，在一些需要考虑时效性、数据同步或者日志记录等业务场景中可能会用到这个时间信息，例如客户端可以根据时间戳来判断数据是否是最新的等情况。
     */
    private Long timestamp;

    // 签名，可能用于对响应数据进行签名验证等安全相关操作，确保响应数据在传输过程中未被篡改，具体的签名生成和验证逻辑需要结合项目中其他相关部分来确定，此处仅作为响应实体的一个属性进行存储。
    private String sign;

    /**
     * 获取签名的Getter方法，方便外部获取该响应实体中封装的签名信息，用于在需要验证响应数据完整性和安全性的业务场景中使用该签名值进行相应的验证操作。
     */
    public String getSign() {
        return sign;
    }

    /**
     * 设置签名的Setter方法，用于外部给该响应实体的sign字段赋值，例如在生成响应时，根据一定的签名算法计算出签名值后，通过这个方法将签名设置到响应实体中，以保证响应数据的安全性。
     */
    public void setSign(String sign) {
        this.sign = sign;
    }

    /**
     * 获取状态码的Getter方法，供其他类获取该响应实体中封装的状态码信息，客户端或者其他业务逻辑处理层可以通过这个方法获取状态码来判断响应的具体情况，决定后续的业务操作。
     */
    public String getCode() {
        return code;
    }

    /**
     * 设置状态码的Setter方法，用于外部给该响应实体的code字段赋值，例如在创建不同状态的响应实体时（成功、失败等不同情况），通过这个方法将对应的状态码设置到对象中，以便准确反映响应的实际状态。
     */
    public void setCode(String code) {
        this.code = code;
    }

    /**
     * 获取信息的Getter方法，方便获取该响应实体中封装的提示消息内容，客户端可以获取这个消息并展示给用户，或者根据消息进行一些错误提示、业务引导等相关操作。
     */
    public String getMsg() {
        return msg;
    }

    /**
     * 设置信息的Setter方法，用于外部将提示消息赋值给该响应实体的msg字段，比如在构建失败响应时，将具体的错误消息通过这个方法设置到对象中，使得客户端能够知晓具体的错误原因。
     */
    public void setMsg(String msg) {
        this.msg = msg;
    }

    /**
     * 获取数据的Getter方法，供其他类获取该响应实体中封装的具体业务数据内容，在不同的业务接口中，客户端可以通过这个方法获取到相应的查询结果、操作返回的数据等内容，进行后续的展示、处理等操作。
     */
    public T getData() {
        return data;
    }

    /**
     * 设置数据并返回当前响应实体对象自身的方法，方便在链式调用时进行数据设置操作，例如可以连续调用setData方法后再进行其他属性的设置，使代码更加简洁流畅，
     * 常用于构建响应实体并设置其数据部分的业务场景，返回自身对象可以继续进行其他属性的赋值等操作。
     */
    public ServerResponseEntity setData(T data) {
        this.data = data;
        return this;
    }

    /**
     * 获取版本的Getter方法，用于获取该响应实体中封装的版本信息，在涉及到版本兼容性判断、接口升级等业务场景中，可能会通过这个方法获取版本号来进行相应的处理操作。
     */
    public String getVersion() {
        return version;
    }

    /**
     * 设置版本的Setter方法，用于外部给该响应实体的version字段赋值，不过在当前代码中版本号初始化为固定值"mall4j.v230424"，但在项目后续扩展或者特殊需求情况下，可能通过这个方法来动态修改版本号等操作。
     */
    public void setVersion(String version) {
        this.version = version;
    }

    /**
     * 获取时间戳的Getter方法，方便获取该响应实体中封装的时间戳信息，在需要根据响应时间来进行业务逻辑判断（如判断数据时效性、统计响应耗时等）的场景中会用到这个时间戳值。
     */
    public Long getTimestamp() {
        return timestamp;
    }

    /**
     * 设置时间戳的Setter方法，用于外部将时间戳赋值给该响应实体的timestamp字段，例如在响应生成时，获取当前的系统时间戳并通过这个方法设置到对象中，以记录准确的响应生成时间。
     */
    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }

    /**
     * 判断响应是否成功的方法，通过比较当前响应实体的状态码与预定义的表示成功的状态码（ResponseEnum.OK.value()，这里推测ResponseEnum是一个枚举类，OK是其中表示成功的枚举值）是否相等来确定，
     * 如果相等则表示响应成功，返回true；否则返回false，方便在业务逻辑中快速判断响应结果是否符合预期，进而进行不同的后续处理操作。
     */
    public boolean isSuccess() {
        return Objects.equals(ResponseEnum.OK.value(), this.code);
    }

    /**
     * 判断响应是否失败的方法，与isSuccess方法相反，通过取反isSuccess方法的判断结果来确定响应是否失败，即如果状态码与表示成功的状态码不相等，则认为响应失败，返回true；否则返回false，
     * 同样用于在业务逻辑中根据响应情况进行相应的错误处理、提示等操作。
     */
    public boolean isFail() {
        return!Objects.equals(ResponseEnum.OK.value(), this.code);
    }

    /**
     * 默认构造函数，在创建ServerResponseEntity对象时，如果没有显式传入参数，会调用这个构造函数进行初始化操作，在这里主要是将版本号初始化为"mall4j.v230424"，
     * 其他成员变量则保持默认的初始值（如null、0等，根据其类型而定），为后续根据具体业务需求设置其他属性值做好准备。
     */
    public ServerResponseEntity() {
        // 版本号
        this.version = "mall4j.v230424";
    }

    /**
     * 创建表示成功且带有具体数据的响应实体的静态方法，首先创建一个ServerResponseEntity对象实例，然后通过链式调用setData方法将传入的数据设置到响应实体中，
     * 再将状态码设置为表示成功的状态码（ResponseEnum.OK.value()），最后返回这个构建好的响应实体对象，方便在业务逻辑中当接口请求成功并需要返回具体数据时快速创建对应的响应实体。
     *
     * @param data 具体的业务数据内容，根据不同的接口请求和业务场景，其类型可以是各种Java对象，例如商品列表、用户信息等，将被封装到响应实体的data属性中返回给客户端。
     * @param <T> 泛型参数，表示响应实体中数据部分的类型，其具体类型由传入的实际参数决定，在调用该方法时，Java编译器会根据传入的数据类型自动推断出T的具体类型。
     * @return 返回构建好的表示成功且包含具体数据的ServerResponseEntity对象，客户端可以接收并解析这个响应实体，获取其中的数据和其他相关信息。
     */
    public static <T> ServerResponseEntity<T> success(T data) {
        ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
        serverResponseEntity.setData(data);
        serverResponseEntity.setCode(ResponseEnum.OK.value());
        return serverResponseEntity;
    }

    /**
     * 创建表示成功但不带有具体数据（仅返回成功状态码和默认成功消息）的响应实体的静态方法，创建一个ServerResponseEntity对象实例后，将状态码设置为表示成功的状态码（ResponseEnum.OK.value()），
     * 同时将提示消息设置为ResponseEnum.OK对应的消息（推测ResponseEnum.OK中除了有表示成功的状态码值，还有对应的默认成功消息内容），最后返回这个构建好的响应实体对象，
     * 适用于那些只需要告知客户端请求成功，不需要返回具体业务数据的业务场景，例如删除操作成功等情况。
     *
     * @param <T> 泛型参数，同样用于表示响应实体中数据部分的类型，在这里由于不返回具体数据，所以主要是为了保持方法签名的一致性，方便统一使用这个泛型类来构建不同类型的响应实体。
     * @return 返回构建好的表示成功的ServerResponseEntity对象，客户端接收到这个响应实体后可以根据状态码知晓请求成功，可能进行一些相应的界面提示等操作。
     */
    public static <T> ServerResponseEntity<T> success() {
        ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
        serverResponseEntity.setCode(ResponseEnum.OK.value());
        serverResponseEntity.setMsg(ResponseEnum.OK.getMsg());
        return serverResponseEntity;
    }

    /**
     * 创建表示成功且带有具体数据的响应实体的重载静态方法，接受一个Integer类型的状态码参数，先将其转换为字符串类型（通过调用String.valueOf方法），
     * 然后按照与success(String code, T data)方法类似的逻辑，创建ServerResponseEntity对象实例，设置传入的状态码和数据，最后返回构建好的响应实体对象，
     * 提供了一种可以灵活传入不同状态码（以整数形式传入，方便与一些常见的状态码数字表示方式兼容）来创建成功响应实体的方式，满足特定业务场景下对状态码自定义的需求。
     *
     * @param code 表示成功的状态码，以整数形式传入，会被转换为字符串类型后设置到响应实体的状态码属性中，具体取值和含义由项目内部根据业务需求自行定义。
     * @param data 具体的业务数据内容，将被封装到响应实体的data属性中返回给客户端，其类型根据实际业务场景而定。
     * @param <T> 泛型参数，表示响应实体中数据部分的类型，由传入的数据实际类型决定，用于统一处理不同类型数据的响应实体构建。
     * @return 返回构建好的表示成功且包含指定状态码和具体数据的ServerResponseEntity对象，方便在特定业务场景下按照自定义的状态码返回成功响应给客户端。
     */
    public static <T> ServerResponseEntity<T> success(Integer code, T data) {
        return success(String.valueOf(code), data);
    }

    /**
     * 创建表示成功且带有具体数据的响应实体的重载静态方法，直接接受一个字符串类型的状态码和具体业务数据参数，创建ServerResponseEntity对象实例后，
     * 将传入的状态码和数据分别设置到响应实体的相应属性中，最后返回构建好的响应实体对象，提供了一种更加灵活的方式来创建带有自定义状态码和具体数据的成功响应实体，
     * 以满足不同业务场景下对响应状态码和返回数据的多样化需求。
     *
     * @param code 表示成功的状态码，以字符串形式传入，将直接设置到响应实体的状态码属性中，其具体取值和含义由项目内部根据业务需求自行定义。
     * @param data 具体的业务数据内容，将被封装到响应实体的data属性中返回给客户端，其类型根据实际业务场景而定。
     * @param <T> 泛型参数，表示响应实体中数据部分的类型，由传入的数据实际类型决定，用于统一处理不同类型数据的响应实体构建。
     * @return 返回构建好的表示成功且包含指定状态码和具体数据的ServerResponseEntity对象，方便在各种业务场景下按照自定义要求返回成功响应给客户端。
     */
    public static <T> ServerResponseEntity<T> success(String code, T data) {
        ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
        serverResponseEntity.setCode(code);
        serverResponseEntity.setData(data);
        return serverResponseEntity;
    }

    /**
     * 创建表示前端显示失败消息的响应实体的静态方法，首先会记录传入的失败消息到日志中（通过log.error方法，方便后续排查问题），然后创建一个ServerResponseEntity对象实例，
     * 将传入的失败消息设置到响应实体的msg属性中，同时将状态码设置为表示前端显示失败的特定状态码（ResponseEnum.SHOW_FAIL.value()，推测是专门用于前端展示失败消息的一种状态码定义），
     * 最后返回这个构建好的响应实体对象，用于在业务逻辑中当需要向客户端明确展示某个失败消息时创建对应的响应实体，例如业务规则校验不通过等情况需要告知客户端具体的错误提示内容。
     *
     * @param msg 失败消息，是要展示给客户端的具体错误提示内容，会被设置到响应实体的msg属性中，以便客户端获取并展示给用户，让用户知晓操作失败的原因。
     * @param <T> 泛型参数，表示响应实体中数据部分的类型，在这里通常可以为null，因为主要是为了传递失败消息，不过也可以根据具体业务场景传入一些相关的数据（如错误详情对象等），由业务需求决定。
     * @return 返回构建好的表示前端显示失败消息的ServerResponseEntity对象，客户端接收到这个响应实体后会展示其中的失败消息给用户，提示操作失败。
     */
    public static <T> ServerResponseEntity<T> showFailMsg(String msg) {
        log.error(msg);
        ServerResponseEntity<T> serverResponseEntity = new ServerResponseEntity<>();
        serverResponseEntity.setMsg(msg);
        serverResponseEntity.setCode(ResponseEnum.SHOW_FAIL.value());
        return serverResponseEntity;
    }

    /**
     * 创建表示失败的响应实体的静态方法，根据传入的ResponseEnum枚举类型参数（推测其中定义了不同的失败情况对应的状态码、消息等信息），首先记录这个枚举对应的信息到日志中（方便排查问题），
     * 然后创建一个ServerResponseEntity对象实例，将枚举中的失败消息设置到响应实体的msg属性中，将枚举对应的状态码设置到响应实体的code属性中，最后返回这个构建好的响应实体对象，
     * 用于在业务逻辑中根据不同的业务失败场景（通过不同的ResponseEnum枚举值来区分）创建对应的失败响应实体，统一处理失败情况的响应返回。
     *
     * @param