package xyz.luxnk.lproject.module;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.nutz.aop.interceptor.ioc.TransAop;
import org.nutz.dao.Cnd;
import org.nutz.dao.FieldFilter;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.util.Daos;
import org.nutz.ioc.aop.Aop;
import org.nutz.ioc.loader.annotation.IocBean;
import org.nutz.json.Json;
import org.nutz.lang.Strings;
import org.nutz.lang.util.NutMap;
import org.nutz.mvc.Scope;
import org.nutz.mvc.adaptor.JsonAdaptor;
import org.nutz.mvc.annotation.*;
import xyz.luxnk.lproject.bean.Permission;
import xyz.luxnk.lproject.bean.Role;
import xyz.luxnk.lproject.bean.UserInfo;
import xyz.luxnk.lproject.bean.UserProfile;

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

/**
 * 角色/权限管理
 * 一个用户属于多种角色，拥有多种特许权限，每种角色拥有多种权限
 */
@At("/admin/authority")
@IocBean
@Ok("void") // 避免误写导致敏感信息泄露到服务器外
public class AuthorityModule extends BaseModule {

    @At("/")
    @Ok("jsp:jsp.page.simple_role")
    @RequiresUser
    public void index() {}

    /**************查询类***************/

    /**
     * 用户列表
     * @param query
     * @param pager
     * @return
     */
    @RequiresPermissions("authority:user:query")
    @At
    @Ok("json: {locked: 'password|salt', ignoreNull: true}") // 禁止把password和salt字段进行传输
    public Object users(@Param("query")String query, @Param("..")Pager pager) {
        return ajaxOk(query(UserInfo.class, Cnd.NEW().asc("id"), pager, null));
    }

    /**
     * 角色列表
     * @param query
     * @param pager
     * @return
     */
    @RequiresPermissions("authority:role:query")
    @At
    @Ok("json")
    public Object roles(@Param("query")String query, @Param("..")Pager pager) {
        return ajaxOk(query(Role.class, Cnd.NEW().asc("id"), pager, null));
    }

    /**
     * 权限列表
     * @param query
     * @param pager
     * @return
     */
    @RequiresPermissions("authority:permission:query")
    @At
    @Ok("json")
    public Object permissions(@Param("query")String query, @Param("..")Pager pager) {
        return ajaxOk(query(Permission.class, Cnd.NEW().asc("id"), pager, null));
    }

    /**************用户操作***************/

    /**
     * 更新用户所属角色/特许权限
     * @param user
     * @param roles
     * @param permissions
     */
    @POST
    @AdaptBy(type = JsonAdaptor.class)
    @RequiresPermissions("authority:user:update")
    @At("/user/update")
    @Aop(TransAop.READ_COMMITTED)
    public void updateUser(@Param("user")UserInfo user, @Param("roles")List<Long> roles, @Param("permissions")List<Long> permissions) {

        // 防御一下
        if (user == null)
            return;
        user = dao.fetch(UserInfo.class, user.getId());

        // 就在那么一瞬间，那个用户已经被其他用户删掉了呢
        if (user == null)
            return;
        if (roles != null) {
            List<Role> rs = new ArrayList<Role>(roles.size());
            for (long roleId : roles) {
                Role r = dao.fetch(Role.class, roleId);
                if (r != null) {
                    rs.add(r);
                }
            }
            dao.fetchLinks(user, "roles");
            if (user.getRoles().size() > 0) {
                dao.clearLinks(user, "roles");
            }
            user.setRoles(rs);
            dao.insertRelation(user, "roles");
        }
        if (permissions != null) {
            List<Permission> ps = new ArrayList<Permission>(permissions.size());
            for (long permissionId : permissions) {
                Permission p = dao.fetch(Permission.class, permissionId);
                if (p != null) {
                    ps.add(p);
                }
            }
            dao.fetchLinks(user, "permissions");
            if (user.getPermissions().size() > 0) {
                dao.clearLinks(user, "permissions");
            }
            user.setPermissions(ps);
            dao.insertRelation(user, "permissions");
        }
    }

    /**
     * 用于显示用户-权限修改对话框的信息
     * @param id
     * @return
     */
    @RequiresPermissions("authority:user:udpate")
    @At("/user/fetch/permission")
    @Ok("json")
    public Object fetchUserPermissions(@Param("id")long id) {
        UserInfo userInfo = dao.fetch(UserInfo.class, id);
        if (userInfo == null)
            return ajaxFail("not such user");
        userInfo = dao.fetchLinks(userInfo, "permissions");
        List<Permission> permissions = dao.query(Permission.class, Cnd.orderBy().asc("name"));
        NutMap data = new NutMap();
        data.put("user", userInfo);
        data.put("permissions", permissions);
        return ajaxOk(data);
    }

    /**
     * 用于显示用户-角色修改对话框的信息
     * @param id
     * @return
     */
    @RequiresPermissions("authority:user:udpate")
    @At("/user/fetch/role")
    @Ok("json")
    public Object fetchUserRoles(@Param("id")long id) {
        UserInfo userInfo = dao.fetch(UserInfo.class, id);
        if (userInfo == null)
            return ajaxFail("not such user");
        userInfo = dao.fetchLinks(userInfo, "roles");
        List<Role> roles = dao.query(Role.class, Cnd.orderBy().asc("name"));
        NutMap data = new NutMap();
        data.put("user", userInfo);
        data.put("permissions", roles);
        return ajaxOk(data);
    }

    /**************角色操作***************/

    /**
     * 新增一个角色
     * @param role
     */
    @POST
    @AdaptBy(type = JsonAdaptor.class)
    @RequiresPermissions("authority:role:add")
    @At("/role/add")
    public void addRole(@Param("..")Role role) {
        if (role == null)
            return;
        dao.insert(role);   // 注意，这里并没有没有用insertWith，即总是插入一个无权限角色
    }

    /**
     * 删除一个角色，admin角色禁止删除
     * @param role
     */
    @POST
    @AdaptBy(type = JsonAdaptor.class)
    @RequiresPermissions("authority:role:delete")
    @At("/role/delete")
    public void delRole(@Param("..")Role role) {
        if (role == null)
            return;
        role = dao.fetch(Role.class, role.getId());
        if (role == null)
            return;

        // 不允许删除admin角色
        if ("admin".equals(role.getName()))
            return;
        dao.delete(Role.class, role.getId());
    }

    /**
     * 更新权限的一般信息或所拥有的权限
     * @param role
     * @param permissions
     */
    @POST
    @AdaptBy(type = JsonAdaptor.class)
    @RequiresPermissions("authority:role:update")
    @At("/role/update")
    @Aop(TransAop.SERIALIZABLE)
    public void updateRole(@Param("user")Role role, @Param("permissions")List<Long> permissions) {

        // 防御一下
        if (role == null)
            return;
        if (dao.fetch(Role.class, role.getId()) == null)
            return;
        if (!Strings.isBlank(role.getAlias()) || !Strings.isBlank(role.getDescription())) {
            Daos.ext(dao, FieldFilter.create(Role.class, "alias|desc")).update(role);
        }
        if (permissions != null) {
            List<Permission> ps = new ArrayList<Permission>();
            for (long permissionId : permissions) {
                Permission p = dao.fetch(Permission.class, permissionId);
                if (p != null) {
                    ps.add(p);
                }
            }

            // 如果有老的权限，先清空，后插入新的纪录
            dao.fetchLinks(role, "permissions");
            if (role.getPermissions().size() > 0) {
                dao.clearLinks(role, "permissions");
            }
            role.setPermissions(ps);
            dao.insertRelation(role, "permissions");
        }
    }

    /**
     * 用于显示角色-权限修改对话框的信息
     * @param id
     * @return
     */
    @RequiresPermissions("authority:role:update")
    @At("/role/fetch")
    @Ok("json")
    public Object fetchRolePermissions(@Param("id")long id) {
        Role role = dao.fetch(Role.class, id);
        if (role == null)
            return ajaxFail("not such role");
        role = dao.fetchLinks(role, null);
        List<Permission> permissions = dao.query(Permission.class, Cnd.orderBy().asc("name"));
        NutMap data = new NutMap();
        data.put("role", role);
        data.put("permissions", permissions);
        return ajaxOk(data);
    }

    /**************权限操作***************/

    /**
     * 新增一个权限
     * @param permission
     */
    @POST
    @AdaptBy(type = JsonAdaptor.class)
    @RequiresPermissions("authority:permission:add")
    @At("/permission/add")
    public void addRole(@Param("..")Permission permission) {
        if (permission == null)
            return;
        dao.insert(permission);
    }

    /**
     * 删除一个权限，authority相关权限禁止删除
     * @param permission
     */
    @POST
    @AdaptBy(type = JsonAdaptor.class)
    @RequiresPermissions("authority:permission:delete")
    @At("/permission/delete")
    public void delRole(@Param("..")Permission permission) {
        if (permission == null)
            return;
        permission = dao.fetch(Permission.class, permission.getId());
        if (permission == null)
            return;

        // 不允许删除authority相关权限
        if (permission.getName().contains("authority"))
            return;
        dao.delete(Permission.class, permission.getId());
    }

    /**
     * 修改权限的一般信息
     * @param permission
     */
    @POST
    @AdaptBy(type = JsonAdaptor.class)
    @RequiresPermissions("authority:permission:delete")
    @At("/permission/update")
    public void updateRole(@Param("..")Permission permission) {
        if (permission == null)
            return;
        if (dao.fetch(Permission.class, permission.getId()) == null)
            return;
        permission.setUpdateTime(new Date());
        permission.setCreateTime(null);
        Daos.ext(dao, FieldFilter.create(Permission.class, null, "name", true)).update(permission);
    }

}
