<?php
//namespace Jaga\Controllers;

use Phalcon\Mvc\Model\Query;
use Jaga\Models\PAK\PAKQuestionnaire;
use Jaga\Models\PAK\PAKJenisDokumenQuestionnaire;
use Jaga\Models\PAK\PAKImplementasi;
use Jaga\Models\PAK\PAKVerifikasiImplementasi;
use Jaga\Models\PAK\PAKVerifikasiImplementasiAttachment;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;


class PAKUserController extends BaseController
{
    public $roles_cannot_be_banned;

    public function onConstruct()
    {
        parent::onConstruct();
        $this->checkIsAuthenticated();
        $this->attachmentFolder = 'users_profpic' . DIRECTORY_SEPARATOR;
        $this->roles_cannot_be_banned = [
            'admin_pak'
        ];
    }

    protected function getAllowedRolesToAccess()
    {
        if($this->hasRole('admin_pak')) {
            return [
                'user_pak',
                'admin_pak',
                'verifikator_pak',
                'observer_pak',
                'user_dinas_pak',
                'user_sekolah_pak'
            ];
        }
        elseif($this->hasRole('user_dinas_pak')) {

            return [
                    'user_pak',
                    'user_sekolah_pak',
                ];
        } else {

            return [
                    'user_pak',
                ];
        }
    }

    protected function getAllowedRolesIdToAccess()
    {
        $rolesName = $this->getAllowedRolesToAccess();

        $roles = Roles::find([
            'columns' => 'id',
            'conditions' => 'name in ({names:array})',
            'bind'  => [
                'names' => $rolesName
            ]
        ]);

        $result = [];
        foreach ($roles as $key => $role) {
            $result[] = $role->id;
        }

        if (empty($result)) {
            throw new CustomErrorException(
                BaseResponse::INVALID_REQUEST,
                "Role terkait tidak ditemukan"
            );
        }

        return $result;
    }

    public function getRoles()
    {
        $this->checkScopes(['pak.view.user']);

        $params = $this->validateIndexRequest($this->request);

        $conditions = 'name in ({names:array})';
        $bind = ['names' => $this->getAllowedRolesToAccess()];

        $all = Roles::find([
            'conditions' => $conditions,
            'bind'  => $bind
        ]);
        $total_record = count($all);
        $rows = Roles::find([
            'conditions' => $conditions,
            'bind'  => $bind,
            'limit' => $params['limit'],
            'offset' => $params['offset'],
        ]);

        return new PaginatedResponse(
            $rows,
            $total_record,
            $params['limit'],
            $params['offset']
        );
    }

    public function listUser()
    {
        $this->checkScopes(['pak.manage.user']);

        $params = $this->validateIndexRequest($this->request);

        $result = $this->getList($params);
        return new PaginatedResponse($result['result'], $result['totalRecord'], $result['limit'], $result['offset']);
    }

    public function exportUser()
    {
        $this->checkScopes(['pak.manage.user']);
        $params = $this->validateIndexRequest($this->request);
        unset($params['limit']);
        unset($params['offset']);
        $baseList = $this->getList($params);
        $rows = $baseList['result'];

        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();

        $column = "A";
        $sheet->setCellValue($column."1", "No.");
        $sheet->setCellValue(++$column."1", "ID");
        $sheet->setCellValue(++$column."1", "Username");
        $sheet->setCellValue(++$column."1", "Nama");
        $sheet->setCellValue(++$column."1", "Email");
        $sheet->setCellValue(++$column."1", "Last Login");
        $sheet->setCellValue(++$column."1", "Instansi/Sekolah");
        $sheet->setCellValue(++$column."1", "Jenjang");
        $sheet->setCellValue(++$column."1", "Role");
        $lastColumn = $column;

        $rowIndex = 1;
        foreach ($rows as $row) {
            $column = "A";
            $rowIndex++;
            $roles = [];
            foreach ($row["roles"] as $role) {
                array_push($roles, $role["name"]);
            }
            $sheet->setCellValue($column."".$rowIndex, ($rowIndex - 1));
            $sheet->setCellValue(++$column."".$rowIndex, $row["um_id"]);
            $sheet->setCellValue(++$column."".$rowIndex, $row["um_user_name"]);
            $sheet->setCellValue(++$column."".$rowIndex, $row["nama"]);
            $sheet->setCellValue(++$column."".$rowIndex, $row["email"]);
            $sheet->setCellValue(++$column."".$rowIndex, $row["last_login"]);
            $sheet->setCellValue(++$column."".$rowIndex, ($row["sekolah"][0]["nama"] ?? $row["instansi"]["nama"]));
            $sheet->setCellValue(++$column."".$rowIndex, ($row["sekolah"][0]["jenjang"]["nama_jenjang"] ?? "-"));
            $sheet->setCellValue(++$column."".$rowIndex, implode("|", $roles));
        }

        $styleHeader = [
            'borders' => [
                'allBorders' => [
                    'borderStyle' => Border::BORDER_THIN,
                    'color' => ['argb' => 'FF000000'],
                ],
            ],
            'font'  => [
                'bold'  => true,
                'size'  => 12,
                'name'  => 'Arial'
            ]
        ];

        $styleBody = [
            'borders' => [
                'allBorders' => [
                    'borderStyle' => Border::BORDER_THIN,
                    'color' => ['argb' => 'FF000000'],
                ],
            ],
            'font'  => array(
                'size'  => 9,
                'name'  => 'Arial'
            ),
        ];

        $rangeHeager = 'A1:'.$lastColumn.'1';
        $sheet->getStyle($rangeHeager)->applyFromArray($styleHeader);

        $rangeBody = "A2:".$lastColumn.$rowIndex;
        $sheet->getStyle($rangeBody)->applyFromArray($styleBody);

        $todayLabel = DateHelper::formatTodayIndex();
        $writer = new Xlsx($spreadsheet);
        $filename = $todayLabel . " - Daftar User PAK" .  ".xlsx";
        header('Content-type: application/vnd.ms-excel');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        return $writer->save('php://output');
    }

    protected function validateIndexRequest($request)
    {
        $params = $request->get();
        //  get ([mixed $name], [mixed $filters], [mixed $defaultValue], [mixed $notAllowEmpty], [mixed $noRecursive])
        $params['limit'] = $request->get('limit', null, 8);
        $params['offset'] = $request->get('offset', null, 0);
        $params['keyword'] = $request->get('keyword', null, '');
        $params['order_by'] = $request->get('order_by', null, 'um_id');
        $params['sort'] = $request->get('sort', null, 'desc');
        $params['id_provinsi'] = $request->get('id_provinsi', null, null);
        $params['id_kota_kabupaten'] = $request->get('id_kota_kabupaten', null, null);
        $params['jenjang_id'] = $request->get('jenjang_id', null, null);
        $params['id_instansi_tipe'] = $request->get('id_instansi_tipe', null, null);

        $allowed_order_by = ['um_id', 'instansi_id'/*, 'means'*/];
        $allowed_sort = ['asc', 'desc'];
        //$allowed_roles = $this->getAllowedRolesToAccess();
        $rules = [
            'limit' => ['validators' => ['digit']],
            'offset' => ['validators' => ['digit']],
            'keyword' => ['validators' => []],
            'role' => ['validators' => []],
            'id_provinsi' => ['validators' => ['digit']],
            'id_kota_kabupaten' => ['validators' => ['digit']],
            'id_instansi_tipe' => ['validators' => ['digit']],
            'jenjang_id' => ['validators' => []],
            'h_login' => ['validators' => ['date']],
            'hn_login' => ['validators' => ['date']],
            'order_by' => ['validators' =>  [[
                'name' => 'inclusion_in',
                'params' => $allowed_order_by
            ]]],
            'sort' => ['validators' =>  [[
                'name' => 'inclusion_in',
                'params' => $allowed_sort
            ]]]
        ];

        if (array_key_exists('role', $params)) {
            /*$rules['role'] = ['validators' =>  [[
                'name' => 'inclusion_in',
                'params' => $allowed_roles
            ]]];*/
            $this->checkAllowedRoles(explode(',', $params['role']) );
        }

        $validatedParams = $this->validate($params, $rules);

        return $validatedParams;
    }

    /*
     * Check if user not related to PAK Module
     */
    protected function checkAllowedRoles($roles)
    {
        $allowed_roles = $this->getAllowedRolesToAccess();

        $intersect = array_intersect($roles, $allowed_roles);

        if (empty($intersect)) {
            throw new ValidationException([
                'field' => 'role',
                'message' => 'Roles must be one of ['.implode(',', $allowed_roles).']'
            ]);
        }
    }

    /*
     * list of users pak
     */
    protected function getList($params)
    {

        $query = 'SELECT DISTINCT um_user.um_id, last_login, um_user_name, um_user.email, um_user.nama, foto, uuid_user, is_banned, jenis_kelamin FROM jaga.um_user ';
        $query .= 'right join jaga.users_roles as ur on ur.user_id = um_id ';
        $query .= 'left join jaga.instansi i on i.id = id_instansi ';
//        $query .= 'left join jaga.jwt_data jwt ON jwt.user_id = um_id AND (jwt.login_type IS NULL OR jwt.login_type = \'USER\')';
        $query .= 'left join jaga.users_sekolah us ON us.um_id = um_user.um_id ';
        $query .= 'left join jaga.sekolah s ON s.npsn = us.npsn ';
        $query .= 'left join jaga.jenjang j ON j.id = s.jenjang_id ';

        $queryCount = "
            SELECT COUNT( DISTINCT um_user.um_id ) FROM jaga.um_user 
            RIGHT JOIN jaga.users_roles AS ur ON ur.user_id = um_user.um_id 
            LEFT JOIN jaga.instansi i ON i.id = id_instansi 
            LEFT JOIN jaga.users_sekolah us ON us.um_id = um_user.um_id 
            LEFT JOIN jaga.sekolah s ON s.npsn = us.npsn
            LEFT JOIN jaga.jenjang j ON j.id = s.jenjang_id
        ";

        $bind = [];

        if(array_key_exists('role', $params) && !is_null($params['role'])) {
            $roles = explode(',', $params['role']);

            $ids = [];
            foreach ($roles as $key => $value) {
                $role = Roles::findOrFail("name = '" . $value . "'");
                array_push($ids, $role->id);
            }

            $role_ids_querystring = "(" . implode(', ', $ids) . ")";
            $query .= 'where ur.role_id in ' . $role_ids_querystring . ' AND um_user.um_id IS NOT NULL AND um_user.is_active = true ';
            $queryCount .= 'where ur.role_id in ' . $role_ids_querystring . ' AND um_user.um_id IS NOT NULL AND um_user.is_active = true ';

        } else {
            $role_ids_querystring = "(" . implode(', ', $this->getAllowedRolesIdToAccess()) . ")";
            $query .= 'where ur.role_id in ' . $role_ids_querystring . ' AND um_user.um_id IS NOT NULL ';
            $queryCount .= 'where ur.role_id in ' . $role_ids_querystring . ' AND um_user.um_id IS NOT NULL ';
        }

        if (!empty($params['keyword'])) {
            $query .=  "AND (um_user.nama ilike :keyword or um_user_name ilike :keyword or um_user.email ilike :keyword)";
            $queryCount .=  "AND (um_user.nama ilike :keyword or um_user_name ilike :keyword or um_user.email ilike :keyword)";
            $bind['keyword'] = '%' . $params['keyword'] . '%';
        }

        if ($params['id_provinsi'] != null) {
            $query .= " AND i.id_provinsi = " . $params['id_provinsi'];
            $queryCount .= " AND i.id_provinsi = " . $params['id_provinsi'];
        }
        if ($params['id_kota_kabupaten'] != null) {
            $query .= " AND (i.id_kota_kabupaten = " . $params['id_kota_kabupaten'] . " OR s.kode_kabupaten_dagri = '" . $params['id_kota_kabupaten'] . "')";
            $queryCount .= " AND (i.id_kota_kabupaten = " . $params['id_kota_kabupaten'] . " OR s.kode_kabupaten_dagri = '" . $params['id_kota_kabupaten'] . "')";
//            $query .= " AND i.id_kota_kabupaten = " . $params['id_kota_kabupaten'];
//            $queryCount .= " AND i.id_kota_kabupaten = " . $params['id_kota_kabupaten'];
        }
        if ($params['id_instansi_tipe'] != null) {
            $query .= " AND j.id_instansi_tipe = " . $params['id_instansi_tipe'];
            $queryCount .= " AND j.id_instansi_tipe = " . $params['id_instansi_tipe'];
        }

        if ($params['jenjang_id'] != null) {
            $ids = $params['jenjang_id'];
            $query .= " AND s.jenjang_id in (" . $ids . ")";
            $queryCount .= " AND s.jenjang_id in (" . $ids . ")";
        }

        if (!empty($params['hn_login'])) {
            // user belum pernah login sejak
            // $queryCount = "SELECT COUNT(*) FROM (" . $query . ") x WHERE (last_login < :hn_login OR last_login IS NULL)";
            // $query = "SELECT * FROM (" . $query . ") x WHERE (last_login < :hn_login OR last_login IS NULL)";
            $queryCount .= " AND (last_login < :hn_login OR last_login IS NULL)";
            $query .= " AND (last_login < :hn_login OR last_login IS NULL)";
            $bind['hn_login'] = $params['hn_login'];
        } else if (!empty($params['h_login'])) {
            // user pernah login sejak
            // $queryCount = "SELECT COUNT(*) FROM (" . $query . ") x WHERE last_login >= :h_login";
            // $query = "SELECT * FROM (" . $query . ") x WHERE last_login >= :h_login";
            $queryCount .= " AND last_login >= :h_login";
            $query .= " AND last_login >= :h_login";
            $bind['h_login'] = $params['h_login'];
        }

        $query .= ' GROUP BY um_user.um_id';
        $query .= ' ORDER BY ' . $params['order_by'] . ' ' . $params['sort'];

        if (isset($params['limit'])) {
            $query .= ' LIMIT ' . $params['limit'] . ' OFFSET ' . $params['offset'];
        }

        $rowquery = $this->db->query($query, $bind);
        $rowquery->setFetchMode(\Phalcon\Db::FETCH_ASSOC);
        $rows    = $rowquery->fetchAll();

        if (isset($params['limit'])) {
            $all = $this->db->query($queryCount, $bind);
            $all->setFetchMode(\Phalcon\Db::FETCH_ASSOC);
            $all_record = $all->fetchAll();
            $total_record = $all_record[0]['count'];
        } else {
            $total_record = sizeof($rows);
        }

        $result = [];
        foreach ($rows as $key => $row) {
            $user = UmUser::findFirst([
                "um_user_name = :username:",
                "bind" => [
                    "username" => $row['um_user_name']
                ]
            ]);
            if(!empty($user)) {
                try {
                    $row['instansi'] = (is_null($user->id_instansi) || !$user->instansi ? null : $user->instansi->toSimpleArray(['id', 'nama', 'id_provinsi', 'id_kota_kabupaten']));
                    $row['sekolah'] = [];
                    if (!empty($user->sekolah)) {
                        foreach ($user->sekolah as $sch) {
                            $row['sekolah'][] = $sch->toSimpleArray();
                        }
                    }
                    foreach ($user->roles as $role) {
                        $row['roles'][] = $role->toArray(['id', 'name', 'label', 'description']);
                    }

                    array_push($result, $row);
                } catch (Exception $e) {
                    //IGNORE
                }
            }
        }

        return [
            'result' => $result,
            'totalRecord' => $total_record,
            'limit' => $params['limit'] ?? null,
            'offset' => $params['offset'] ?? null
        ];
    }

    public function register()
    {
        $this->checkScopes(['pak.manage.user']);

        $user = new UmUser();

        $rawBody = $this->request->getJsonRawBody(true);
        $params = $this->validateStoreRequest($rawBody, $user);

        $result = $this->saveUser($user, $params);
        return new CollectionPaginatedResponse([$result]);
    }

    public function registerAdmin()
    {
        $this->checkScopes(['pak.manage.user']);

        $user = new UmUser();

        $rawBody = $this->request->getJsonRawBody(true);
        $params = $this->validateStoreRequest($rawBody, $user);

        $result = $this->saveUser($user, $params);
        return new CollectionPaginatedResponse([$result]);
    }

    public function view($id)
    {
        $this->checkScopes(['pak.view.user']);

        $result = $this->getUserInfo($id);

        return new CollectionPaginatedResponse([$result]);
    }


    public function myProfile()
    {
        $id = $this->shared->user->um_id;
        $result = $this->getUserInfo($id);

        return new CollectionPaginatedResponse([$result]);
    }

    public function updateUser($id)
    {
        $this->checkScopes(['pak.view.user']);
         // only admin or the user itself can update
        $um_id = $this->shared->user->um_id;

        if($this->hasRole('admin_pak') || $this->hasRole('user_dinas_pak') || $id == $um_id) {


            $user = UmUser::findOrFail($id);
            $oldData = LogModeration::extractUmUser($id);

            $rawBody = $this->request->getJsonRawBody(true);
            $params = $this->validateStoreRequest($rawBody, $user);

            try {
                $this->db->begin();
                $result = $this->saveUser($user, $params);

                $newData = LogModeration::extractUmUser($id);
                $action = [LogModeration::ACTION_UPDATE_UMUSER];
                if (array_key_exists('password', $params)) array_push($action, LogModeration::ACTION_CHANGEPWD_UMUSER);
                LogModeration::loggedUmUser(
                    $action,
                    LogModeration::ACTIONMENU_ADMINISTRASI_PAK,
                    $id,
                    $oldData,
                    $newData,
                    $um_id
                );

                $this->db->commit();
                return new CollectionPaginatedResponse([$result]);
            } catch (\Exception $e) {
                $this->db->rollback();
                throw $e;
            }
        }
        else  {
            throw new CustomErrorException(
                BaseResponse::INVALID_ACTION,
                'User not allowed to perform this action'
            );
        }
    }

    protected function validateStoreRequest($request, $user)
    {
        $allowed_gender = ['L','P','T'];

        $rules = [
            'username' => ['validators' => [
                'required',
                'alpha_dash',
                [
                    'name' => 'min_string',
                    'params' => 6
                ]
            ]],
            'email' => ['validators' => ['required', 'email']],
            'nama' => ['validators' => ['required']],
            'foto' => ['validators' => []],
            'uuid_user' => ['validators' => []],
            'roles' => ['validators' =>  ['required']],
            'phone' => ['validators' => ['required', 'digit']],
            'jenis_kelamin' => ['validators' =>  [[
                'name' => 'inclusion_in',
                'params' => $allowed_gender
            ]]],
        ];

        // if new record, must have a password
        if($user->um_id == null) {
            $request['password'] = AuthHelper::decryptPassword($request);
            $request['confirm_password'] = AuthHelper::decryptPassword($request, 'confirm_password', 'h_confirm_password');
            $rules['password'] = ['validators' => [
                'required',
                'confirm_password',
                [
                    'name' => 'min_string',
                    'params' => 8
                ]
            ]];
            $rules['confirm_password'] = ['validators' => ['required']];
            AuthHelper::validatePassword($request['password']);
        }
        elseif (array_key_exists('password', $request) || array_key_exists('h_password', $request)) {
            $request['password'] = AuthHelper::decryptPassword($request);
            $request['confirm_password'] = AuthHelper::decryptPassword($request, 'confirm_password', 'h_confirm_password');
            $rules['password'] = ['validators' => [
                'confirm_password',
                [
                    'name' => 'min_string',
                    'params' => 8
                ]
            ]];
            AuthHelper::validatePassword($request['password']);
        }

        // validate roles input format
        if (
            array_key_exists('roles', $request)
            && (!is_array($request['roles'])
                || empty($request['roles']))
        ) {
            throw new ValidationException([
                'field' => 'roles',
                'message' => 'Roles tidak boleh kosong. Format roles salah'
            ]);
        } elseif (array_key_exists('roles', $request)) {
            $roles = $request['roles'];
            $allowed_roles = $this->getAllowedRolesToAccess();
            $roles_error_message = 'must be one of ['.implode(',', $allowed_roles).']';
            foreach ($roles as $key => $value) {
                if(!in_array($value, $allowed_roles)) {
                    throw new ValidationException([
                        'field' => 'roles',
                        'message' => $roles_error_message
                    ]);
                }
            }
        }

        // if user_sekolah_pak, npsn_sekolah cannot be blank
        if (
            array_key_exists('roles', $request)
            && in_array('user_sekolah_pak', $request['roles'])
        ) {
            $rules['npsn_sekolah'] = ['validators' => ['required']];
        } else {
            $rules['npsn_sekolah'] = ['validators' => []];
        }

        // if user_dinas_pak, id_instansi cannot be blank
        if (
            array_key_exists('roles', $request)
            && in_array('user_dinas_pak', $request['roles'])
        ) {
            $rules['id_instansi'] = ['validators' => ['required']];
        } else {
            $rules['id_instansi'] = ['validators' => []];
        }

        $instansiExists = false;
        if(array_key_exists('id_instansi', $request)) {
            $instansiExists = \Instansi::findOrFail($request['id_instansi']);
        }

        $sekolahExists = false;
        if(array_key_exists('npsn_sekolah', $request)) {
            $sekolahExists = \Sekolah::findOrFail("npsn = '" . $request['npsn_sekolah'] . "'");
        }

        if ($instansiExists && $sekolahExists) {
            if ($instansiExists->id_provinsi == 31 && !empty($sekolahExists->Jenjang)) {
                $instansiOverride = null;
                if ($sekolahExists->Jenjang->id_instansi_tipe == 1) {
                    $instansiOverride = Instansi::findFirst([
                        'conditions' => 'id_provinsi = :id_provinsi: and id_tipe = 1',
                        'bind' => ['id_provinsi' => 31]
                    ]);
                } else if ($sekolahExists->Jenjang->id_instansi_tipe == 2 && !empty($sekolahExists->kode_kabupaten_dagri)) {
                    $instansiOverride = Instansi::findFirst([
                        'conditions' => 'id_kota_kabupaten = :id_kota_kabupaten: and id_tipe = 2',
                        'bind' => ['id_kota_kabupaten' => $sekolahExists->kode_kabupaten_dagri]
                    ]);
                }

                if ($instansiOverride) {
                    $request['id_instansi'] = $instansiOverride->id;
                }
            }
        }

        $params = $this->filterExpectedRequest($request, $rules);

        \UserHelper::validateUsernameAvailability($params['username'], $user->um_user_name);
        \UserHelper::validateEmailAvailability($params['email'], $user->email);
        \UserHelper::validatePhoneAvailability($params['phone'], $user->phone);


        return $params;
    }

    protected function saveUser($user, $params)
    {
        $roles = $params['roles'];
        unset($params['roles']);

        $user->assign($params);
        $user->um_user_name = $params['username'];
        $user->um_tenant_id = -1234;
        $user->um_changed_time = date("Y-m-d H:i:s");

        if(array_key_exists('password', $params)) {
            $hashed_password = base64_encode(hash("sha256", $params['password'], true));
            $user->um_user_new_password = $this->security->hash($params['password']);
            $user->um_user_password = $hashed_password;
        }

        $saved = $user->save();

        $users_roles = Roles::find([
            'conditions' => 'name in ({roles:array})',
            'columns' => 'id',
            'bind' => [
                'roles' => $roles
            ]
        ])->toArray();

        $user_roles_ids = [];
        foreach ($users_roles as $key => $role) {
            array_push($user_roles_ids, $role['id']);
        }

        $user->syncRoles($user_roles_ids);

        if (!is_null($params['npsn_sekolah'])) {
            $user->syncSekolahWithNpsn([$params['npsn_sekolah']]);
        }

        return $this->getUserInfo($user->um_id);
    }

    public function uploadProfilePicture($request)
    {
        $postRequest = $this->request->getPost();

        $validatedRequest = $this->validate($postRequest, [
            'keterangan' => ['validators' => []],
            'metadata' => ['validators' => []]
        ]);

        $service = new AttachmentService($this->shared, $this->minio);
        $validationConfig = [
            'allowed-types' => [
                "image/jpg",
                "image/jpeg",
                "image/png",
                "image/gif",
            ],
        ];
        $attachmentConfig = [
            'tipe' => Attachments::TIPE_PUBLIC,
        ];
        $attachments = $service->upload(
            getenv("FILESYSTEM_CLOUD"),
            $validationConfig,
            $attachmentConfig,
            $this->request,
            $this->attachmentFolder
        );

        return new CollectionPaginatedResponse($attachments);
    }

    public function ban($id)
    {
        $this->checkScopes(['pak.manage.user']);

        $model = UmUser::findOrFail($id);
        $oldData = LogModeration::extractUmUser($id);
        $this->checkNotRelatedModuleUser($model);

        foreach ($this->roles_cannot_be_banned as $key => $role) {
            if ($model->hasRole($role)) {
                throw new CustomErrorException(
                    BaseResponse::INVALID_ACTION,
                    'The selected user cannot be banned'
                );
            }
        }

        if(!$this->hasOneOfRoles(['admin_pak','user_dinas_pak'])) {
            throw new CustomErrorException(
                BaseResponse::INVALID_ACTION,
                'User not allowed to perform this action'
            );
        }

        if ($this->hasRole('user_dinas_pak') && !$this->hasRole('admin_pak')) {
            $instansi = $this->shared->user->instansi;
            $allowed_npsn = $instansi->getSekolahNpsn();

            $allowed_to_ban = false;
            foreach ($allowed_npsn as $key => $npsn) {
                if ($model->hasNpsn($npsn)) {
                    $allowed_to_ban = true;
                    break;
                }
            }
            if (!$allowed_to_ban) {
                throw new CustomErrorException(
                    BaseResponse::INVALID_ACTION,
                    'User not allowed to perform this action'
                );
            }
        }

        if ($model->is_banned) {
            throw new CustomErrorException(BaseResponse::INVALID_ACTION, 'User already banned');
        }

        $model->is_banned = true;
        $saved = $model->save();

        if (!$saved) {
            $this->throwValidationException($model->getMessages());
        }

        $newData = LogModeration::extractUmUser($id);
        LogModeration::loggedUmUser(
            [LogModeration::ACTION_BAN_UMUSER],
            LogModeration::ACTIONMENU_ADMINISTRASI_PAK,
            $id,
            $oldData,
            $newData,
            $this->shared->user->um_id
        );

        return new CollectionPaginatedResponse([$model->baseToArray()]);

    }

    public function unban($id)
    {
        $this->checkScopes(['pak.manage.user']);

        $model = UmUser::findOrFail($id);
        $oldData = LogModeration::extractUmUser($id);
        $this->checkNotRelatedModuleUser($model);

        if (!$model->is_banned) {
            throw new CustomErrorException(BaseResponse::INVALID_ACTION, 'User already active');
        }

        $model->is_banned = false;

        if (!$model->save()) {
            $this->throwValidationException($model->getMessages());
        } else {
            $newData = LogModeration::extractUmUser($id);
            LogModeration::loggedUmUser(
                [LogModeration::ACTION_UNBAN_UMUSER],
                LogModeration::ACTIONMENU_ADMINISTRASI_PAK,
                $id,
                $oldData,
                $newData,
                $this->shared->user->um_id
            );

            return new CollectionPaginatedResponse([$model->baseToArray()]);
        }
    }

    public function isUsernameAvailable($username) {
        $params = $this->request->get();
        $this->validate($params, ['validations' => ['id' => ['digit']]]);

        // handle case update user
        if (!empty($params['id'])) {
            $user = UmUser::findFirst($params['id']);
            if ($user) {
                return new SimpleResponse(UserHelper::isUsernameAvailable(strtolower($username), strtolower($user->um_user_name)));
            }
        }
        return new SimpleResponse(UserHelper::isUsernameAvailable($username));
    }

    public function isEmailAvailable() {
        $rawBody = $this->request->getJsonRawBody(true);

        $validatedParams = $this->validate($rawBody, [
            'id' => ['validators' => ['digit']],
            'email' => ['validators' => ['required']]
        ]);

        $email = $validatedParams['email'];

        // handle case update user
        if (!empty($rawBody['id'])) {
            $user = UmUser::findFirst($rawBody['id']);
            if ($user) {
                return new SimpleResponse(UserHelper::isEmailAvailable(strtolower($email), strtolower($user->email)));
            }
        }
        return new SimpleResponse(UserHelper::isEmailAvailable($email));
    }

    public function isUsernameEmailAvailable() {
        $rawBody = $this->request->getJsonRawBody(true);
        $validatedParams = $this->validate($rawBody, [
            'id' => ['validators' => ['digit']],
            'username' => ['validators' => ['required']],
            'email' => ['validators' => ['required']],
        ]);

        $username = $validatedParams['username'];
        $email = $validatedParams['email'];

        // handle case update user
        if (!empty($rawBody['id'])) {
            $user = UmUser::findFirst($rawBody['id']);
            if ($user) {
                $availability = UserHelper::isUsernameAvailable(strtolower($username), strtolower($user->um_user_name));
                if (!$availability) {
                    return new SimpleResponse([
                        "available" => $availability,
                        "message" => "Username telah digunakan"
                    ]);
                }
                $availability = UserHelper::isEmailAvailable(strtolower($email), strtolower($user->email));
                if (!$availability) {
                    return new SimpleResponse([
                        "available" => $availability,
                        "message" => "Email telah digunakan"
                    ]);
                }

                return new SimpleResponse([
                    "available" => $availability
                ]);
            }
        }
        $availability = UserHelper::isUsernameAvailable(strtolower($username));
        if (!$availability) {
            return new SimpleResponse([
                "available" => $availability,
                "message" => "Username telah digunakan"
            ]);
        }
        $availability = UserHelper::isEmailAvailable(strtolower($email));
        if (!$availability) {
            return new SimpleResponse([
                "available" => $availability,
                "message" => "Email telah digunakan"
            ]);
        }

        return new SimpleResponse([
            "available" => $availability
        ]);
    }

    /*
     * Check if user not related to PAK Module
     */
    protected function checkNotRelatedModuleUser($user)
    {
        $user_roles = $user->roles;
        $user_roles_ids = [];
        foreach ($user_roles as $key => $role) {
            $user_roles_ids[] = $role->id;
        }

        $allowed_roles_ids = $this->getAllowedRolesIdToAccess();

        $intersect = array_intersect($user_roles_ids, $allowed_roles_ids);

        if (empty($intersect)) {
            throw new CustomErrorException(
                BaseResponse::INVALID_ACTION,
                'User cannot ban the selected user'
            );
        }
    }


    protected function getUserInfo($userId)
    {
        $user = UmUser::findOrFail($userId);

        $columns = [
            'um_id',
            'um_user_name',
            'email',
            'nama',
            'tempat_lahir',
            'foto',
            'presigned_url',
            'presigned_exp',
            'phone',
            'uuid_user',
            'tgl_lahir',
            'is_banned',
            'jenis_kelamin',
            'id_instansi'
        ];

        $result = $user->toArray($columns);
        //var_dump($user->id_instansi);
        $result['instansi'] = (is_null($user->id_instansi) || !$user->instansi ? null : $user->instansi->toArrayWithCityAndProvince());
        $result["profile_picture_url"] = MediaHelper::getPresignedUrlFoto($result, UmUser::class, $this->config, $this->minio);

        return $result;
    }
    /*
    public function setProfilePicture(){}
    public function resetEmailPassword()
    {
    }*/

}
