<?php
declare (strict_types = 1);

namespace app\admin\controller\v1;

use app\admin\exception\InvalidOperateException;
use app\admin\model\v1\SysMenuModel;
use app\admin\model\v1\SysRoleAuthorityModel;
use app\admin\model\v1\SysRoleModel;
use app\admin\validate\v1\SysRoleValidate;
use think\facade\Log;

/**
 * 角色管理控制器
 */
class Role
{
    // 角色分页
    public function index()
    {
        $params = request()->get([
            'name',
            'page/d' => 1,
            'size/d' => 10
        ]);

        $roles = SysRoleModel::withoutField([
                'pid',
                'created_at',
                'updated_at',
                'deleted_at'
            ])
            ->withSearch(['name'], [
                'name' => $params['name']??null
            ])
            ->order('id', 'desc');
        if (!request()->has('scene')) {
            $roles = $roles->paginate([
                'list_rows' => $params['size'],
                'page'      => $params['page']
            ]);
            if (!$roles->isEmpty()) {
                $roles_id  = array_column($roles->items(), 'id');
                $authority = SysMenuModel::alias('menu')
                    ->field(['menu.title', 'authority.role_id'])
                    ->join('sys_role_authority authority', 'authority.menu_id = menu.id')
                    ->whereIn('authority.role_id', $roles_id)
                    ->select();
                if (!empty($authority)) {
                    $authority_map = [];
                    foreach ($authority as $v) {
                        $authority_map[$v['role_id']][] = $v['title'];
                    }
                    $roles->each(function($item) use($authority_map) {
                        $item['authority'] = [];
                        if (isset($authority_map[$item['id']])) {
                            $item['authority'] = array_unique($authority_map[$item['id']]);
                        }
                    });
                }
            }
        } else if ('all' == request()->param('scene')) {
            $roles = $roles->select();
        }

        return success('获取成功', $roles);
    }

    // 角色详情
    public function read()
    {
        $id = request()->param('id');

        $role = SysRoleModel::withoutField([
                'pid',
                'created_at',
                'updated_at',
                'deleted_at'
            ])
            ->with(['authorities'])
            ->bypk($id)
            ->find()
            ->hidden(['authorities.role_id']);
        if (empty($role)) {
            return error('角色不存在');
        }

        return success('获取成功', $role);
    }

    // 角色新增
    public function save()
    {
        $post = request()->post([
            'name',
            'desc',
            // $[*].menu_id
            // $[*].permissions
            'menu_permission' => '[]'
        ]);
        $post['menu_permission'] = json_decode($post['menu_permission'], true);

        $validate = new SysRoleValidate;
        if (!$validate->scene('create')->check($post)) {
            return error($validate->getError());
        }

        SysRoleModel::startTrans();
        try {
            $role = SysRoleModel::create($post, ['name', 'desc']);
            if ($role->isEmpty()) {
                throw new InvalidOperateException('角色新增失败');
            }

            if (!empty($post['menu_permission'])) {
                $permissions = [];
                foreach ($post['menu_permission'] as $menu) {
                    if (!isset($menu['permissions'])) {
                        $permissions[] = [
                            'role_id'    => $role->id,
                            'menu_id'    => $menu['menu_id'],
                        ];
                        continue;
                    }
                    foreach ($menu['permissions'] as $permission) {
                        $permissions[] = [
                            'role_id'    => $role->id,
                            'menu_id'    => $menu['menu_id'],
                            'permission' => $permission
                        ];
                    }
                }
                $authority = (new SysRoleAuthorityModel)->saveAll($permissions);
                if ($authority->isEmpty()) {
                    throw new InvalidOperateException('角色权限新增失败');
                }
            }

            SysRoleModel::commit();
        } catch (InvalidOperateException $e) {
            SysRoleModel::rollback();
            return error($e->getMessage());
        } catch (\Throwable $th) {
            SysRoleModel::rollback();
            Log::error($th->getMessage());
            return error('操作失败');
        }

        return success('操作成功');
    }

    // 角色更新
    public function update()
    {
        $id  = request()->param('id');
        $put = request()->put([
            'name',
            'desc',
            // $[*].menu_id
            // $[*].permissions
            'menu_permission' => '[]'
        ]);
        $put['menu_permission'] = json_decode($put['menu_permission'], true);

        $validate = new SysRoleValidate;
        if (!$validate->scene('update')->check(array_merge($put, ['id' => $id]))) {
            return error($validate->getError());
        }

        SysRoleModel::startTrans();
        try {
            $role = SysRoleModel::bypk($id)->find();
            if (empty($role)) {
                throw new InvalidOperateException('角色不存在');
            }

            if (!$role->allowField(['name', 'desc'])->save($put)) {
                throw new InvalidOperateException('角色更新失败');
            }

            if (!empty($put['menu_permission'])) {
                $permissions = [];
                foreach ($put['menu_permission'] as $menu) {
                    if (!isset($menu['permissions'])) {
                        $permissions[] = [
                            'role_id'    => $role->id,
                            'menu_id'    => $menu['menu_id'],
                        ];
                        continue;
                    }
                    foreach ($menu['permissions'] as $permission) {
                        $permissions[] = [
                            'role_id'    => $role->id,
                            'menu_id'    => $menu['menu_id'],
                            'permission' => $permission
                        ];
                    }
                }

                SysRoleAuthorityModel::roleId($role->id)->delete();
                $authority = (new SysRoleAuthorityModel)->saveAll($permissions);
                if ($authority->isEmpty()) {
                    throw new InvalidOperateException('角色权限更新失败');
                }
            }

            SysRoleModel::commit();
        } catch (InvalidOperateException $e) {
            SysRoleModel::rollback();
            return error($e->getMessage());
        } catch (\Throwable $th) {
            SysRoleModel::rollback();
            Log::error($th->getMessage());
            return error('操作失败');
        }

        return success('操作成功');
    }

    // 角色删除
    public function delete()
    {
        $id = request()->param('id');

        $role = SysRoleModel::bypk($id)->find();
        if (empty($role)) {
            return error('请确认要操作对象是否存在');
        }

        if (1 == $role->is_system) {
            return error('该角色禁止删除');
        }

        if (!$role->delete()) {
            return error('操作失败');
        }

        return success('操作成功');
    }
}
