<?php
/**
 * Created by PhpStorm.
 * Author: woann <304550409@qq.com>
 * Date: 18-10-26下午1:23
 * Desc: 管理员
 */

namespace App\Http\Controllers\Admin;

use App\AdminMenu;
use App\AdminPermission;
use App\AdminRole;
use App\AdminUser;
use App\Http\Controllers\Controller;
use App\Http\helper\Helper;
use App\Services\GoogleAuthenticatorService;
use App\Utility\Rbac;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Redis;

class AdministratorController extends Controller
{
    /**
     * @Desc: 菜单列表
     * @Author: woann <304550409@qq.com>
     * @return \Illuminate\View\View
     */
    public function menuList()
    {
        // 获取一级菜单
        return view('admin.menu', ['list' => AdminMenu::where('pid', 0)->get()]);
    }

    /**
     * @Desc: 添加菜单
     * @Author: woann <304550409@qq.com>
     * @param Request $request
     * @return \Illuminate\View\View
     */
    public function menuAddView(Request $request)
    {
        $roles = AdminRole::get();
        $topMenu = AdminMenu::where('pid', 0)->get();
        return view('admin.menu_add', ['roles' => $roles, 'top_menu' => $topMenu]);
    }

    public function menuAdd(Request $request)
    {
        $data = $request->except(['role', 's']);
        $roles = new Collection($request->input('roles'));
        if ($roles->isEmpty()) {
            return $this->json(500, '未选择任何角色');
        }
        $menu = new AdminMenu();
        $menu->fill($data);
        $menu->save();
        // 保存菜单所属角色
        $roles->map(function ($roleId) use ($menu) {
            $role = AdminRole::find($roleId);
            $menu->roles()->attach($role);
        });
        return $this->json(200, '添加成功');
    }

    /**
     * @Desc: 修改菜单
     * @Author: woann <304550409@qq.com>
     * @param Request $request
     * @param $id
     * @return \Illuminate\View\View
     */
    public function menuUpdateView(Request $request, $id)
    {
        $roles = AdminRole::get();
        $menu = AdminMenu::findOrFail($id);
        $roles->map(function ($role) use ($menu) {
            $menu->roles->each(function ($mRole) use (&$role) {
                if ($mRole->id === $role->id) {
                    $role->checked = true;
                }
            });
            return $role;
        });
        $topMenu = AdminMenu::where('pid', 0)->get();
        return view('admin.menu_update', [
            'roles' => $roles,
            'top_menu' => $topMenu,
            'menu' => $menu,
        ]);
    }

    public function menuUpdate(Request $request, $id)
    {
        $menu = AdminMenu::findOrFail($id);
        $roles = new Collection($request->input('roles'));
        if ($roles->isEmpty()) {
            return $this->json(500, '未选择任何角色');
        }
        // 基础信息更新
        $data = $request->except(['role', 's']);
        $menu->fill($data)->save();
        // 删除原有关联数据
        $menu->roles()->detach();
        // 重新关联数据
        $roles->each(function ($roleId) use ($menu) {
            $role = AdminRole::find($roleId);
            $menu->roles()->attach($role);
        });
        return $this->json(200, '修改成功');
    }

    /**
     * @Desc: 删除菜单
     * @Author: woann <304550409@qq.com>
     * @param $id
     * @return mixed
     */
    public function menuDel($id)
    {
        $menu = AdminMenu::findOrFail($id);
        $menu->roles()->detach();
        $menu->delete();
        return $this->json(200, '删除成功');
    }

    public function roleList()
    {
        return view('admin.role', [
            'list' => AdminRole::paginate(10),
        ]);
    }

    /**
     * @Desc: 添加角色
     * @Author: woann <304550409@qq.com>
     * @param Request $request
     * @return \Illuminate\View\View
     */
    public function roleAddView(Request $request)
    {
        return view('admin.role_add', [
            'permissions' => AdminPermission::get(),
        ]);
    }

    public function roleAdd(Request $request)
    {
        $param = $request->post();
        $role = new AdminRole();
        $role->fill($param);
        $role->save();
        if (isset($param['permissions'])) {
            (new Collection($param['permissions']))->map(function ($permissionId) use ($role) {
                $permission = AdminPermission::find($permissionId);
                $role->permissions()->attach($permission);
            });
        }
        return $this->json(200, "添加成功");
    }

    /**
     * @Desc: 修改角色
     * @Author: woann <304550409@qq.com>
     * @param Request $request
     * @param $id
     * @return \Illuminate\View\View
     */
    public function roleUpdateView(Request $request, $id)
    {
        $role = AdminRole::findOrFail($id);
        $permissions = AdminPermission::get();
        $permissions->map(function ($permission) use ($role) {
            $permission->checked = false;
            $role->permissions->each(function ($rPermission) use ($role, &$permission) {
                if ($rPermission->id === $permission->id) {
                    $permission->checked = true;
                    return false;
                }
            });
            return $permission;
        });
        return view('admin.role_update', ['role' => $role, 'permissions' => $permissions]);
    }

    public function roleUpdate(Request $request, $id)
    {
        $param = $request->post();
        $role = AdminRole::findOrFail($id);
        $role->fill($param);
        $role->save();
        // 删除所有权限关联
        $role->permissions()->detach();
        // 录入权限关联
        if (isset($param['permissions'])) {
            (new Collection($param['permissions']))->map(function ($permissionId) use ($role) {
                $permission = AdminPermission::find($permissionId);
                $role->permissions()->attach($permission);
            });
        }
        return $this->json(200, "修改成功");

    }

    /**
     * @Desc: 删除角色
     * @Author: woann <304550409@qq.com>
     * @param $id
     * @return mixed
     */
    public function roleDel($id)
    {
        if ($id == 1) {
            return $this->json(500, '超级管理员不可删除');
        }
        $role = AdminRole::findOrFail($id);
        // 删除所有多对多关系
        $role->users()->detach();
        $role->menus()->detach();
        $role->permissions()->detach();
        $role->delete();
        return $this->json(200, '删除成功');
    }

    /**
     * @return mixed
     * 权限列表
     */
    public function permissionList()
    {
        return view('admin.permission', [
            'list' => AdminPermission::get(),
        ]);
    }

    /**
     * @param Request $request
     * @return mixed
     * 添加权限
     */
    public function permissionAddView(Request $request)
    {
        //渲染页面
        $routes = Rbac::getAllRoutes();
        // foreach ($routes as $key => $value) {
        //     print_r(json_decode(json_encode($value),true));
        // }
        return view('admin.permission_add', ['routes' => $routes]);
        // return view('admin.permission_add', ['routes' => AdminMenu::orderBy('id')->get()]);
    }

    public function permissionAdd(Request $request)
    {
        $data = $request->post();
        $permission = new AdminPermission();
        $permission->fill($data);
        $permission->save();
        return $this->json(200, '添加成功');
    }

    /**
     * @param Request $request
     * @param $id
     * @return mixed
     * 修改权限
     */
    public function permissionUpdateView(Request $request, $id)
    {
        $permission = AdminPermission::findOrFail($id);
        $rbacRoutes = Rbac::getAllRoutes();
        $checkRoutes = $permission->routes->map(function ($route) {
            $routeObj = new \StdClass();
            $routeObj->rbacRule = $route;
            return $routeObj;
        });
        $uncheckRoutes = new Collection();
        $rbacRoutes->each(function ($route) use ($permission, $checkRoutes, &$uncheckRoutes) {
            $uncheckFlag = true;
            $checkRoutes->each(function ($checkRoute) use ($route, &$uncheckFlag) {
                if ($route->rbacRule === $checkRoute->rbacRule) {
                    $uncheckFlag = false;
                }
            });
            if ($uncheckFlag) {
                $uncheckRoutes->push($route);
            }
        });
        return view('admin.permission_update', [
            'permission' => $permission,
            'uncheck_routes' => $uncheckRoutes,
            'check_routes' => $checkRoutes,
        ]);
    }

    public function permissionUpdate(Request $request, $id)
    {
        $data = $request->post();
        $permission = AdminPermission::findOrFail($id);
        $permission->fill($data);
        $permission->save();
        return $this->json(200, '修改成功');

    }

    /**
     * @return mixed
     * 删除权限
     */
    public function permissionDel($id)
    {
        $permission = AdminPermission::findOrFail($id);
        // 解除所有多对多关系
        $permission->roles()->detach();
        $permission->delete();
        return $this->json(200, '删除成功');
    }

    /**
     * @return mixed
     * 管理员列表
     */
    public function administratorList()
    {
//        $admin_user = AdminUser::pluck('account','id')->toArray();

        $admins = AdminUser::paginate(10);
        $admin_ids = [];
        foreach ($admins as &$val) {
            $admin_ids[] = $val->id;
        }
        $history_lottery_amount = DB::table('agent.dbo.admin_score')->where(['type' => 1])->whereIn('admin_id', $admin_ids)->selectRaw('IsNull(sum(change_score),0)as change_score,admin_id')->groupBy('admin_id')->pluck('change_score', 'admin_id')->toArray();
        $history_recharge_amount = DB::table('agent.dbo.admin_score')->where(['type' => 2])->whereIn('admin_id', $admin_ids)->selectRaw('IsNull(sum(change_score),0)as change_score,admin_id')->groupBy('admin_id')->pluck('change_score', 'admin_id')->toArray();


        foreach ($admins as &$val) {

            $val->history_lottery_amount = isset($history_lottery_amount[$val->id]) ? $history_lottery_amount[$val->id] : '';
            $val->history_recharge_amount = isset($history_recharge_amount[$val->id]) ? $history_recharge_amount[$val->id] : '';
        }
        return view('admin.administrator', [
            'admins' => $admins,
        ]);
    }

    /**
     * @param Request $request
     * @return mixed
     * 添加管理员
     */
    public function administratorAddView(Request $request)
    {
        $roles = AdminRole::select('id', 'name')->get();

        $channels = DB::table('QPPlatformDB.dbo.ChannelPackageName')
                      ->pluck('Channel', 'Channel');

        $types = [1 => '管理后台', 2 => '渠道后台', 3 => '数据统计新后台'];
        return view('admin.administrator_add', ['roles' => $roles, 'types' => $types,'channels'=>$channels]);
    }

    public function administratorAdd(Request $request)
    {
        $post = $request->post();

        $post['channel'] = json_encode($post['channel']);

        $roles = (new Collection($request->post('roles')));
        if (AdminUser::isExist($post['account'], $post['type'])) {
            return $this->json(500, '该账号已存在');
        }
        $admin = new AdminUser();
        $admin->fill($post);
        $admin->save();
        $roles->map(function ($roleId) use ($admin) {
            $role = AdminRole::find($roleId);
            $admin->roles()->attach($role);
        });
        return $this->json(200, '添加成功');
    }

    public function administratorUpdateView(Request $request, $id)
    {
        $roles = AdminRole::select('id', 'name')->get();
        $admin = AdminUser::findOrFail($id);
        $selectRoleIdArr = [];
        $admin->roles->map(function ($role) use (&$selectRoleIdArr) {
            $selectRoleIdArr[] = $role->id;
        });
        $admin->channel = json_decode($admin->channel,true);

        $channels = DB::table('QPPlatformDB.dbo.ChannelPackageName')
                      ->pluck('Channel', 'Channel');

        $ga = $this->buildGaPayload($admin);

        return view('admin.administrator_update', [
            'admin' => $admin,
            'roles' => $roles,
            'channels'=>$channels,
            's_role_id_arr' => $selectRoleIdArr,
            'ga' => $ga,

        ]);
    }

    public function administratorUpdate(Request $request, $id)
    {
        $post = $request->post();
        $roles = (new Collection($request->post('roles')));
        $admin = AdminUser::findOrFail($id);
        if ($admin->isExistForUpdate($post['account'], $post['type'])) {
            return $this->json(500, '该账号已存在');
        }
        $post['channel'] = json_encode($post['channel']);
        $post['ga_enabled'] = empty($post['ga_enabled']) ? 0 : 1;

        if ($post['ga_enabled'] == 1 && empty($post['ga_secret'])) {
            return $this->json(500, '请先生成GA密钥');
        }
        $post = array_filter($post, function ($value, $key) {
            if ($key === 'ga_enabled') {
                return true;
            }
            return !($value === null || $value === '');
        }, ARRAY_FILTER_USE_BOTH);

        $admin->fill($post)->save();


        // 删除用户的所有关联角色
        $admin->roles()->detach();
        $roles->map(function ($roleId) use ($admin) {
            $role = AdminRole::find($roleId);
            $admin->roles()->attach($role);
        });
        return $this->json(200, '修改成功');

    }

    public function resetGaSecret($id)
    {
        $admin = AdminUser::findOrFail($id);
        $gaService = new GoogleAuthenticatorService();
        $secret = $gaService->generateSecret(32);

        $admin->ga_secret = $secret;
        $admin->ga_enabled = 0;
        $admin->save();

        return $this->json(200, 'GA密钥已重置，请扫码后再启用', $this->buildGaPayload($admin));
    }

    /**
     * @return mixed
     * 删除管理员
     */
    public function administratorDel($id)
    {
        $admin = AdminUser::findOrFail($id);
        // 解除管理员角色多对多关系
        $admin->roles()->detach();
        $admin->delete();
        return $this->json(200, '删除成功');
    }

    public function administratorBlock($id)
    {
        $admin = AdminUser::where('id', $id)->value('status');
        if ($admin == 1) {
            AdminUser::where('id', $id)->update(['status' => -1]);
            return apiReturnSuc('success', '禁用成功');
        } else {
            AdminUser::where('id', $id)->update(['status' => 1]);
            return apiReturnSuc('success', '启用成功');
        }
    }


    /**
     * @param Request $request
     * @return mixed
     * 后台登录
     */
    public function login(Request $request)
    {
        if(!isset($_SERVER['HTTP_ACCEPT_LANGUAGE']))return '';//$_SERVER['HTTP_ACCEPT_LANGUAGE']="zh_CN";
        $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 5); //只取前4位，这样只判断最优先的语言。如果取前5位，可能出现en,zh的情况，影响判断。
        if (preg_match("/zh/i", $lang)){
            \App::setLocale("zh_CN");
        }else{
            \App::setLocale("en_US");
        }
        return view('admin.login');
    }

    /**
     * 后台登录图形验证码（GD）
     */
    public function loginCaptcha(Request $request)
    {
        if (!function_exists('imagecreatetruecolor')) {
            abort(503, 'GD extension required');
        }

        $chars = '23456789ABCDEFGHJKLMNPQRSTUVWXY';
        $code = '';
        $len = strlen($chars) - 1;
        for ($i = 0; $i < 4; $i++) {
            $code .= $chars[random_int(0, $len)];
        }
        $request->session()->put('admin_login_captcha', strtolower($code));

        $w = 120;
        $h = 42;
        $im = imagecreatetruecolor($w, $h);
        $bg = imagecolorallocate($im, 248, 249, 250);
        imagefilledrectangle($im, 0, 0, $w, $h, $bg);
        for ($i = 0; $i < 5; $i++) {
            $lineColor = imagecolorallocate($im, random_int(180, 230), random_int(180, 230), random_int(180, 230));
            imageline($im, random_int(0, $w), random_int(0, $h), random_int(0, $w), random_int(0, $h), $lineColor);
        }
        for ($i = 0; $i < 50; $i++) {
            $px = imagecolorallocate($im, random_int(150, 200), random_int(150, 200), random_int(150, 200));
            imagesetpixel($im, random_int(0, $w - 1), random_int(0, $h - 1), $px);
        }
        $textColor = imagecolorallocate($im, random_int(40, 90), random_int(40, 90), random_int(40, 90));
        imagestring($im, 5, 32, 13, $code, $textColor);

        ob_start();
        imagepng($im);
        imagedestroy($im);
        $png = ob_get_clean();

        return response($png, 200)
            ->header('Content-Type', 'image/png')
            ->header('Cache-Control', 'no-store, no-cache, must-revalidate, max-age=0')
            ->header('Pragma', 'no-cache');
    }

    public function checkLogin(Request $request)
    {
        $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 5); //只取前4位，这样只判断最优先的语言。如果取前5位，可能出现en,zh的情况，影响判断。
        if (preg_match("/zh/i", $lang)){
            \App::setLocale("zh_CN");
        }else{
            \App::setLocale("en_US");
        }

        $post = $request->post();
        if (empty($post['account'])) {
            return $this->json(500, trans('cs.login.notice_user'));
        }
        if (empty($post['password'])) {
            return $this->json(500, trans('cs.login.notice_pass'));
        }

        $captchaInput = isset($post['captcha']) ? strtolower(trim((string) $post['captcha'])) : '';
        $captchaSession = (string) $request->session()->pull('admin_login_captcha', '');
        if ($captchaInput === '' || $captchaSession === '' || !hash_equals($captchaSession, $captchaInput)) {
            return $this->json(500, trans('cs.login.wrong_captcha'));
        }

        $admin = AdminUser::where('account', $post['account'])->first();

        if (empty($admin) || $admin->type != 1) {
            return $this->json(500, trans('cs.login.cannotfinduser'));
        }
        if (!password_verify($post['password'], $admin->password)) {
            return $this->json(500, trans('cs.login.wrongpass'));
        }
        if ($admin->status == -1) {
            return $this->json(500, trans('cs.login.block'));
        }
        if ((int) $admin->ga_enabled !== 1 || empty($admin->ga_secret)) {
            return $this->json(500, trans('cs.login.ga_required'));
        }

        $gaCode = isset($post['ga_code']) ? trim((string) $post['ga_code']) : '';
        if ($gaCode === '') {
            return $this->json(500, trans('cs.login.notice_ga_code'));
        }
        $gaService = new GoogleAuthenticatorService();
        if (!$gaService->verifyCode($admin->ga_secret, $gaCode)) {
            return $this->json(500, trans('cs.login.wrong_ga_code'));
        }

        $roles = $admin->roles;

        $ip = $request->ip();


        // 超管不验证IP白名单
        $whiteListId = [];//[1, 12, 2010];
        foreach ($roles as $role) {
            if (in_array($role->id, $whiteListId)) {
                $white_ip = DB::table('agent.dbo.ip_white_list')->where('ip', $ip)->first();
                if (!$white_ip) {
//                    return $this->json(500, '请联系管理员添加IP白名单！'.$ip);
                }
            }
        }
//
//
//        // 添加ip登录管理
//        $ip_data = [
//            'admin_id' => $admin->id,
//            'ip' => $ip,
//            'ip_address' => Helper::get_ip_city($ip),
//            'last_login_time' => date('Y-m-d H:i:s')
//        ];

//        $_where = [
//            'admin_id' => $admin->id,
//            'ip' => $ip
//        ];
//        $query = DB::table('agent.dbo.admin_login_ip')->where($_where)->first();
//        if (!$query) {
//        DB::table('agent.dbo.admin_login_ip')->insert($ip_data);
//        }


        $request->session()->put('admin', $admin);
        return $this->json(200, trans('cs.login.notice'));

    }

    /**
     * @param Request $request
     * @param $id
     * @return mixed
     * 修改信息
     */
    public function editInfoView(Request $request, $id)
    {
        return view('admin.edit_info', ['admin' => AdminUser::findOrFail($id)]);
    }

    public function editInfo(Request $request, $id)
    {
        $post = $request->post();
        $admin = AdminUser::findOrFail($id);
        $admin->fill($post);
        $admin->save();
        $request->session()->put('admin', $admin);
        return $this->json(200, '修改成功');
    }

    /**
     * @param Request $request
     * @return mixed
     * 退出登录
     */
    public function logout(Request $request)
    {
        $admin_id=$request->session()->get("admin")->id;
        $adminKey="adminuser_$admin_id";
        Redis::del($adminKey);
        $request->session()->flush();
        return redirect('/admin/login_op');
    }

    protected function buildGaPayload(AdminUser $admin)
    {
        $secret = $admin->ga_secret ?: '';
        $gaService = new GoogleAuthenticatorService();
        $issuer = config('app.name', 'Admin');
        $otpAuthUrl = '';
        $qrCodeUrl = '';

        if ($secret !== '') {
            $otpAuthUrl = $gaService->getOtpAuthUrl($issuer, $admin->account, $secret);
            $qrCodeUrl = $gaService->getQrCodeUrl($otpAuthUrl, 200);
        }

        return [
            'secret' => $secret,
            'otpauth_url' => $otpAuthUrl,
            'qr_code_url' => $qrCodeUrl,
            'enabled' => (int) $admin->ga_enabled,
        ];
    }

}
