package cn.lihongjie.coal.resource.entity;

import cn.lihongjie.coal.base.entity.CommonEntity;
import cn.lihongjie.coal.permission.entity.PermissionEntity;

import io.vavr.collection.Stream;

import jakarta.persistence.*;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.Fetch;

import java.util.ArrayList;
import java.util.List;

@Data
@Entity
@Comment("资源")
@Slf4j
@Table(indexes = {@Index(name = "idx_resource_type_code", columnList = "type,code", unique = true)})
@Cacheable
public class ResourceEntity extends CommonEntity {

    @ManyToMany(mappedBy = "resources")
    @org.hibernate.annotations.Cache(
            usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)
    @Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
    private List<PermissionEntity> permissions;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
    @org.hibernate.annotations.Cache(
            usage = org.hibernate.annotations.CacheConcurrencyStrategy.READ_WRITE)
    @Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
    private List<ResourceEntity> children;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id", foreignKey = @ForeignKey(value = ConstraintMode.NO_CONSTRAINT))
    private ResourceEntity parent;

    @Comment("资源类型 0 菜单 1 按钮 3 url")
    private String type;

  

    @Comment("资源地址")
    private String url;

    @Comment("需要机构管理员权限")
    private Boolean orgAdmin = false;

    @Comment("需要系统管理员权限")
    private Boolean sysAdmin = false;

    @Comment("匿名用户可以访问")
    private Boolean anonymous = false;

    @Comment("图标")
    private String icon;

    @Comment("是否可见")
    private Boolean visible;

    @Comment("其他数据")
    private String metadata;


    @Comment("检查签名")
    private Boolean signCheck;


    @Comment("是否限流")
    private Boolean rateLimit;


    @Comment("是否校验提交token")
    private Boolean submitToken;



    private static String getParent(String path) {
        log.debug("getParent {}", path);

        return "/" + StringUtils.join(Stream.of(StringUtils.split(path, "/")).dropRight(1), "/");
    }

    public void addChildren(ResourceEntity newRs) {

        //        log.debug();("addChildren1 {} {}", this.getUrl(), newRs.getUrl());
        if (this.children == null) {
            this.children = new ArrayList<>();
        }

        if (newRs.getUrl().equals(this.getUrl())) {
            log.debug("添加子节点  当前url {} 子节点url {} 退出....", this.getUrl(), newRs.getUrl());
            return;
        }

        for (ResourceEntity child : this.children) {

            if (newRs.getUrl().equals(child.getUrl())) {
                return;
            }

            boolean isChildren = isChildren(newRs, child);
            log.debug("isChildren {} c: {} p: {}", isChildren, newRs.getUrl(), child.getUrl());
            if (isChildren) {

                child.addChildren(newRs);

                return;
            }
        }

        ResourceEntity r = new ResourceEntity();

        String tmp = newRs.getUrl();

        while (!isSamePath(this.getUrl(), getParent(tmp))) {
            tmp = getParent(tmp);
        }

        r.setUrl(tmp);

        r.setName(r.getUrl());
        r.setType("3");
        r.setParent(this);
        r.setChildren(new ArrayList<>());
        r.setCode(r.getUrl());

        this.children.add(r);
        //        log.debug();("addChildren2 {} {}", r.getUrl(), this.getUrl());
        log.debug(
                "添加子节点  当前url {} 子节点url {} 添加一个新节点 {}  ",
                this.getUrl(),
                newRs.getUrl(),
                r.getUrl());

        r.addChildren(newRs);
    }

    private boolean isChildren(ResourceEntity c, ResourceEntity p) {

        if (!isSamePath(c.getUrl(), p.getUrl())) {
            // 判断list是否有相同前缀

            String[] pl = StringUtils.split(p.getUrl(), "/");
            String[] cl = StringUtils.split(c.getUrl(), "/");

            for (int i = 0; i < pl.length; i++) {
                if (i >= cl.length) {
                    return false;
                }
                if (!pl[i].equalsIgnoreCase(cl[i])) {
                    return false;
                }
            }

            return true;
        }
        return false;
    }

    private boolean isSamePath(String a, String b) {
        return a.equalsIgnoreCase(b) || (a + "/").equalsIgnoreCase(b);
    }
}
