package org.springblade.common.auth;

import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.springblade.common.auth.support.Application;
import org.springblade.common.auth.support.Department;
import org.springblade.common.auth.support.Menu;
import org.springblade.common.auth.support.MenuV2;
import org.springblade.common.auth.support.Operation;
import org.springblade.common.auth.support.Permission;
import org.springblade.common.auth.support.Role;
import com.wn.common.datamodel.Long2StringSerializer;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.springframework.util.CollectionUtils;

/**
 * @author caiyihua
 */
@Data
@NoArgsConstructor
public class UserContext implements Serializable {

    public static final long INNER_LOGIN_USER_ID = 999L;

    public static final String ALL_PERMISSION_CODE = "*";

    private static final long serialVersionUID = 1L;

    @JsonSerialize(using = Long2StringSerializer.class)
    private Long userId;

    private String accessToken = "";

    private String loginName;

    private String userName;

    private String telephone;

    @JsonSerialize(using = Long2StringSerializer.class)
    private Long staffId;

    @Deprecated
    private Long companyId;

    private String extBusinessIds;
    /**
     * 自定义对象，供扩展使用
     */
    private String jsonObject;

    @Deprecated
    private List<Department> departments = new ArrayList<>();

    @Deprecated
    private List<Role> roles = new ArrayList<>();

    @Deprecated
    private List<Permission> permissions = new ArrayList<>();

    @Deprecated
    private List<Menu> menus = new ArrayList<>();

    private List<Application> applications = new ArrayList<>();

    private List<Operation> operations = new ArrayList<>();

    public boolean isInnerLoginUser() {
        return userId == INNER_LOGIN_USER_ID;
    }

    @Deprecated
    public boolean isContainPermissionCode(String code) {
        //内部登录账号的权限code为"*",表示拥有所有权限
        if (permissions.size() >= 1 && permissions.get(0).getCode().equals(ALL_PERMISSION_CODE)) {
            return true;
        }
        for (Permission p : permissions) {
            if (p.getCode().equalsIgnoreCase(code)) {
                return true;
            }
        }
        return false;
    }

    public boolean isContainOperationCode(String code, String requestUrl) {
        for (Operation operation : operations) {
            if (operation.getCode().equalsIgnoreCase(code) && operation.getRequestUrl().equals(requestUrl)) {
                return true;
            }
        }
        return false;
    }

    public Operation getOperationByCode(String code) {
        for (Operation operation : operations) {
            if (operation.getCode().equalsIgnoreCase(code)) {
                return operation;
            }
        }
        return null;
    }

    public Application getCurrentApplication(String code, String requestUrl) {
        if (applications.size() == 1) {
            return applications.get(0);
        }

        for (Application application : applications) {
            if (!CollectionUtils.isEmpty(application.getMenus())) {
                for (MenuV2 menuV2 : application.getMenus()) {
                    if (menuContainsOperationCode(menuV2, code, requestUrl)) {
                        return application;
                    }
                }
            }
        }

        return null;
    }

    private boolean menuContainsOperationCode(MenuV2 menuV2, String code, String requestUrl) {
        List<Operation> operationList = menuV2.getOperations();
        if (!CollectionUtils.isEmpty(menuV2.getChildren())) {
            for (MenuV2 child : menuV2.getChildren()) {
                if (menuContainsOperationCode(child, code, requestUrl)) {
                    return true;
                }
            }
        } else if (!CollectionUtils.isEmpty(operationList)){
            for (Operation operation : operationList) {
                if (operation.getCode().equalsIgnoreCase(code) && operation.getRequestUrl().equals(requestUrl)) {
                    return true;
                }
            }
        }

        return false;
    }

    public UserContext(Builder builder) {
        this.userId = builder.userId;
        this.loginName = builder.loginName;
        this.userName = builder.userName;
        this.telephone = builder.telephone;
        this.staffId = builder.staffId;
        this.companyId = builder.companyId;
        this.departments = builder.departments;
        this.roles = builder.roles;
        this.permissions = builder.permissions;
        this.menus = builder.menus;
        this.extBusinessIds = builder.extBusinessIds;
        this.jsonObject = builder.jsonObject;
        this.applications = builder.applications;
        this.operations = builder.operations;
    }

    public static Builder custom() {
        return new Builder();
    }

    public static class Builder {
        private long userId;
        private String loginName;
        private String userName;
        private String telephone;
        private long staffId;
        @Deprecated
        private long companyId;
        @Deprecated
        private List<Department> departments = new ArrayList<>();
        @Deprecated
        private List<Role> roles = new ArrayList<>();
        @Deprecated
        private List<Permission> permissions = new ArrayList<>();
        @Deprecated
        private List<Menu> menus = new ArrayList<>();
        private String extBusinessIds;
        private String jsonObject;
        private List<Application> applications = new ArrayList<>();
        private List<Operation> operations = new ArrayList<>();

        public Builder() {

        }

        public Builder userId(long userId) {
            this.userId = userId;
            return this;
        }

        public Builder loginName(String loginName) {
            this.loginName = loginName;
            return this;
        }

        public Builder userName(String userName) {
            this.userName = userName;
            return this;
        }

        public Builder telephone(String telephone) {
            this.telephone = telephone;
            return this;
        }

        public Builder staffId(long staffId) {
            this.staffId = staffId;
            return this;
        }

        public Builder companyId(long companyId) {
            this.companyId = companyId;
            return this;
        }

        public Builder departments(List<Department> departments) {
            this.departments = departments;
            return this;
        }

        public Builder roles(List<Role> roles) {
            this.roles = roles;
            return this;
        }

        public Builder permissions(List<Permission> permissions) {
            this.permissions = permissions;
            return this;
        }

        public Builder menus(List<Menu> menus) {
            this.menus = menus;
            return this;
        }

        public Builder extBusinessIds(String extBusinessIds) {
            this.extBusinessIds = extBusinessIds;
            return this;
        }

        public Builder jsonObject(String jsonObject) {
            this.jsonObject = jsonObject;
            return this;
        }

        public Builder applications(List<Application> applications) {
            this.applications = applications;
            return this;
        }

        public Builder operations(List<Operation> operations) {
            this.operations = operations;
            return this;
        }

        public UserContext build() {
            return new UserContext(this);
        }

    }

}
