/* (C) 2022 YiRing, Inc. */
package com.yiring.auth.domain.permission;

import static com.yiring.auth.domain.permission.Permission.DELETE_SQL;
import static com.yiring.auth.domain.permission.Permission.TABLE_NAME;

import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.yiring.common.domain.BasicEntity;
import io.hypersistence.utils.hibernate.type.json.JsonType;
import jakarta.persistence.*;
import java.io.Serial;
import java.io.Serializable;
import java.util.Objects;
import lombok.*;
import lombok.experimental.FieldDefaults;
import lombok.experimental.FieldNameConstants;
import lombok.experimental.SuperBuilder;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.SQLRestriction;
import org.hibernate.proxy.HibernateProxy;

/**
 * 权限
 *
 * @author ifzm
 * 2018/9/3 17:08
 */

@Getter
@Setter
@SuperBuilder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@FieldNameConstants
@FieldDefaults(level = AccessLevel.PRIVATE)
@SQLDelete(sql = DELETE_SQL + BasicEntity.Where.WHERE_ID)
//@SQLDeleteAll(sql = DELETE_SQL)
@SQLRestriction(BasicEntity.Where.EXIST)
@Entity
@Table(
    name = TABLE_NAME,
    indexes = {
        @Index(columnList = BasicEntity.Fields.deleted),
        @Index(columnList = Permission.Fields.type),
        @Index(columnList = Permission.Fields.pid),
        @Index(columnList = Permission.Fields.tree),
    }
)
@Comment("系统权限")
public class Permission extends BasicEntity implements Serializable {

    public static final String TABLE_NAME = "SYS_PERMISSION";
    public static final String DELETE_SQL = "update " + TABLE_NAME + BasicEntity.Where.DELETE_SET;

    @Serial
    private static final long serialVersionUID = -2001221843529000953L;

    @Comment("类型(MENU: 菜单, BUTTON: 按钮)")
    @Column(nullable = false)
    @Enumerated(EnumType.STRING)
    Type type;

    @Comment("序号")
    Integer serial;

    @Comment("标识")
    @Column(nullable = false)
    String uid;

    @Comment("名称")
    @Column(nullable = false)
    String name;

    @Comment("路径")
    String path;

    @Comment("重定向")
    String redirect;

    @Comment("组件")
    String component;

    @Comment("图标")
    String icon;

    @Comment("是否隐藏")
    Boolean hidden;

    @Comment("是否禁用")
    @Column(columnDefinition = "bool default false", nullable = false)
    Boolean disabled;

    @Comment("权限父级ID")
    String pid;

    @Comment("树节点标识")
    String tree;

    /**
     * 可用于扩展一些前端可能用到的路由参数
     */
    @Comment("扩展元数据信息")
    @org.hibernate.annotations.Type(JsonType.class)
    @Column(columnDefinition = "json")
    JSONObject meta;

    @SuppressWarnings({ "unused" })
    public enum Type {
        /**
         * 目录/平台
         */
        DIR("目录"),

        /**
         * 菜单
         */
        MENU("菜单"),

        /**
         * 按钮
         */
        BUTTON("按钮");

        final String name;

        Type(String name) {
            this.name = name;
        }

        @JsonCreator
        public static Type of(String type) {
            for (Type value : values()) {
                if (value.name().equalsIgnoreCase(type)) {
                    return value;
                }
            }
            return null;
        }
    }

    /**
     * 获取权限的元数据信息，通常是根据前端所需来输出，可自定义调整
     *
     * @return JSON 格式 Meta 元数据
     */
    public JSONObject getMetaJson() {
        JSONObject meta = new JSONObject();
        meta.put("title", this.name);
        meta.put("icon", this.icon);
        meta.put("orderNo", this.serial);
        meta.put("hideMenu", this.hidden);
        if (this.meta != null) {
            meta.putAll(this.meta);
        }
        return meta;
    }

    @Override
    public final boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null) {
            return false;
        }
        Class<?> oEffectiveClass = o instanceof HibernateProxy
            ? ((HibernateProxy) o).getHibernateLazyInitializer().getPersistentClass()
            : o.getClass();
        Class<?> thisEffectiveClass = this instanceof HibernateProxy
            ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass()
            : this.getClass();
        if (thisEffectiveClass != oEffectiveClass) {
            return false;
        }
        Permission that = (Permission) o;
        return getId() != null && Objects.equals(getId(), that.getId());
    }

    @Override
    public final int hashCode() {
        return this instanceof HibernateProxy
            ? ((HibernateProxy) this).getHibernateLazyInitializer().getPersistentClass().hashCode()
            : getClass().hashCode();
    }
}
