package com.dtok.api.controller;

import cn.dev33.satoken.annotation.SaCheckPermission;

import com.dtok.entity.Account;
import com.dtok.entity.AccountRole;
import com.dtok.entity.RolePermission;
import com.dtok.framework.exception.BizExceptionEnum;
import com.dtok.framework.exception.ServiceException;
import com.dtok.framework.response.ResponseData;
import com.dtok.framework.util.ToolUtil;
import com.dtok.repository.AccountRepository;
import com.dtok.repository.AccountRoleRepository;
import com.dtok.repository.RolePermissionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.persistence.criteria.Predicate;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

@RestController
@RequestMapping("role")
public class RoleController {

    @Autowired
    AccountRoleRepository roleRepository;

    @Autowired
    AccountRepository userRepository;

    @Autowired
    RolePermissionRepository rolePermissionRepository;

    @GetMapping("/search")
    @ResponseBody
    public ResponseData search(@RequestParam(value = "code", required = false) String code, @RequestParam(value = "name", required = false) String name) {
        Specification<AccountRole> query = (root, query1, criteriaBuilder) -> {
            Predicate predicate = criteriaBuilder.conjunction();
            if (ToolUtil.isNotEmpty(code)) {
                predicate.getExpressions().add(criteriaBuilder.or(criteriaBuilder.equal(root.get("code"), code)));
            }
            if (ToolUtil.isNotEmpty(name)) {
                predicate.getExpressions().add(criteriaBuilder.or(criteriaBuilder.like(root.get("name"), "%" + name + "%")));
            }
            return predicate;
        };
        List<AccountRole> roleList = roleRepository.findAll(query);
        return ResponseData.success(roleList);
    }

    @GetMapping("/authRole/{userCode}/{roleCode}")
    @SaCheckPermission("role")
    public ResponseData roleAuthorization(@PathVariable String roleCode, @PathVariable String userCode) {
        Optional<AccountRole> roleOptional = roleRepository.findById(roleCode);
        Account account = userRepository.findUserByUsername(userCode);
        if (!roleOptional.isPresent()) {
            throw new NullPointerException(BizExceptionEnum.ROLE_ERROR.getMessage());
        }
        if (Objects.isNull(account)) {
            throw new NullPointerException(BizExceptionEnum.USER_NOT_EXISTED.getMessage());
        }

        if (account.getRoleCode().equals(Account.FINAL_ROLE)) {
            throw new ServiceException(BizExceptionEnum.CANT_CHANGE_ADMIN);
        }

        account.setRoleCode(roleOptional.get().getCode());
        userRepository.save(account);
        return ResponseData.success("授权成功!");
    }

    @PostMapping("/update/{oldCode}")
    @SaCheckPermission("role")
    @Transactional(rollbackFor = Exception.class)
    public ResponseData update( AccountRole role, @PathVariable String oldCode) {
        if (Objects.isNull(role)) {
            throw new NullPointerException("角色不能为空");
        }
        role.setCode(oldCode);
        roleRepository.save(role);
        return ResponseData.success("修改成功");
    }

    @GetMapping("/delete/{code}")
    @SaCheckPermission("role")
    @Transactional(rollbackFor = Exception.class)
    public ResponseData delete(@PathVariable String code) {
        List<Account> users = userRepository.findUsersByRoleCode(code);
        if (users.isEmpty()) {
            Optional<AccountRole> roleOptional = roleRepository.findById(code);
            if (!roleOptional.isPresent()) {
                throw new NullPointerException("角色不存在");
            }
            List<RolePermission> rolePermissions = rolePermissionRepository.findRolePermissionsByRoleCode(code);
            rolePermissionRepository.deleteAll(rolePermissions);
            roleRepository.delete(roleOptional.get());
            return ResponseData.success("删除成功");
        } else {
            throw new ServiceException(400, "该角色正在被使用，无法删除");
        }
    }

    @PostMapping("/add")
    @SaCheckPermission("role")
    public ResponseData add(AccountRole role) {
        roleRepository.save(role);
        return ResponseData.success("添加完成");
    }
}
