<?php

/*
 * *************************************************
 * Copyright (C) 2021 Earworks.                    *
 * Codeigniter Project Template Modification       *
 * Please contact our email for more information : *
 * contact@earworks.co.id                          *
 * *************************************************
 */

defined('BASEPATH') OR exit('No direct script access allowed');
require_once __DIR__ . DIRECTORY_SEPARATOR . 'MY_Controller_Trait_Api.php';

/**
 * Description of MY_Controller
 *
 * @author Andhy Taslin <andhy@earworks.co.id>
 * @since 1.0
 */
class MY_Controller extends CI_Controller {

    const CODE_SUCCESS = '200';
    const CODE_ERROR = '501';
    const CODE_NOT_FOUND = '502';
    const CODE_INVALID_PARAMETER = '503';
    const CODE_INVALID_REQUEST = '504';
    const CODE_PERMISSION_DENIED = '701';
    const CODE_LOGIN_EXPIRED = '702';
    const CODE_NOT_LOGIN = '703';
    const CODE_TOO_MANY_ATTEMPT = '704';
    const CODE_VERSION_INVALID = '900';

    use MY_Controller_Trait_Api;

    public static $field_time = 'timestamp';
    public static $field_status = 'status';
    public static $field_message = 'message';
    public static $field_data = 'data';
    protected $user = [];

    public function __construct() {
        parent::__construct();
        $directory = $this->router->fetch_directory();
        if ($directory == 'backoffice/') {
            $token_session = TOKEN_SESSION_BACKOFFICE;
            $token_cookie = TOKEN_COOKIE_BACKOFFICE;
        } elseif ($directory == 'event/') {
            $token_session = TOKEN_SESSION_EVENT;
            $token_cookie = TOKEN_COOKIE_EVENT;
        } elseif ($directory == 'api/') {
            $token_session = TOKEN_SESSION_EVENT;
            $token_cookie = TOKEN_COOKIE_EVENT;
            return;
        } else {
            $token_session = TOKEN_SESSION;
            $token_cookie = TOKEN_COOKIE;
        }
        $this->user = $this->session->userdata($token_session);
        if (!$this->user) {
            $token = isset($_COOKIE[$token_cookie]) ? $_COOKIE[$token_cookie] : null;
            $user = null;
            if ($token) {
                $user = User_model::get_dbo()->where('login_token', $token)->first();
            }
            if ($user && ($session = $this->_get_user_info($user))) {
                $this->session->set_userdata($token_session, $session);
                $this->user = $session;
            }
        } else {
            if (!isset($this->user['user']['id'])) {
                $this->session->set_flashdata('danger', lang('invalid_session'));
                redirect('login');
            }
            // once again check validity of session value
            $user = User_model::get_dbo()->where('id', $this->user['user']['id'])->first();
            if (!$user) {
                // if not valid
                $user_obj = new User_model();
                $user_obj->logout($this->user['user']['id']);
                $this->session->set_flashdata('danger', lang('invalid_session'));
                redirect('login');
            }
            $session = $this->_get_user_info($user);
            if (!$session) {
                $user->logout($user->id);
                $this->session->set_flashdata('danger', lang('invalid_session'));
                redirect('login');
            } else {
                $this->session->set_userdata($token_session, $session);
            }
        }
        // checking for the first time login 
//        if ($this->user['user']['password_default'] && strpos(current_url(), 'change-profile') === false && $this->session->flashdata('changed_password') != 1
//        ) {
////            $this->session->set_flashdata('success', lang('first_time_login'));
//            redirect('dashboard/change-profile');
//        }
    }

    protected function granted_public($permission, $redirect_and_message = true) {
        return $this->_granted(User_model::LOGIN_TYPE_PUBLIC, $permission, $redirect_and_message);
    }

    protected function granted_backoffice($permission, $redirect_and_message = true) {
        return $this->_granted(User_model::LOGIN_TYPE_BACKOFFICE, $permission, $redirect_and_message);
    }

    private function _get_user_info($user = null) {
        $profile = $user->profile;
        $roles = $user->roles;
        $permissions = $user->get_permissions();
        if (!$profile || !$roles || !$permissions || !$user) {
            return false;
        } else {
            return [
                'user' => $user->toArray(),
                'profile' => $profile->toArray(),
                'login_types' => $roles->pluck('login_type')->toArray(),
                'permissions' => $permissions->pluck('name', 'id')->toArray()
            ];
        }
    }

    private function _granted($login_type, $permission, $redirect_and_massage) {
        if (!$this->user) {
            if ($redirect_and_massage === true) {
                $this->session->set_flashdata('danger', lang('session_expired'));
                redirect('login/index');
            }
            return false;
        }
        $role_accept = false;
        foreach ($this->user['login_types'] as $type) {
            if ($login_type == $type) {
                $role_accept = true;
            }
        }
        if ($role_accept === false) {
            if ($redirect_and_massage === true) {
                $this->session->set_flashdata('danger', lang('permission_denied'));
                redirect('login/index');
            }
            return false;
        }
        $permission_granted = in_array($permission, $this->user['permissions']);
        if ($permission_granted === false) {
            if ($redirect_and_massage === true) {
                $this->session->set_flashdata('danger', lang('access_denied'));
                redirect('dashboard');
            }
            return false;
        }
        return true; // valid login, roles, and permission
    }

    /**
     * <pre>
     * You can define like:
     * $this->validate_form(['field1', 'field2']);
     * <b>OR:</b>
     * $this->validate_form([
     * &nbsp;&nbsp;&nbsp;&nbsp;'field1' => 'trim|required',
     * &nbsp;&nbsp;&nbsp;&nbsp;'field2' => 'trim|valid_email',
     * ]);
     * <b>OR:</b>
     * $this->validate_form([
     * &nbsp;&nbsp;&nbsp;&nbsp;'field1' => [
     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'rules' => 'trim|required|min_length[12]',
     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'message' => [
     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'min_length' => '{field} must have at least {param} characters.',
     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;'required' => 'You have not provided %s.'
     * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;],
     * &nbsp;&nbsp;&nbsp;&nbsp;],
     * &nbsp;&nbsp;&nbsp;&nbsp;'field2' => 'trim|valid_email',
     * ]);
     * </pre>
     * @param array $fields
     * @param boolean $as_json true for json | false for error array information
     * @return mixed true if not error | json/array of error information
     */
    protected function validate_form($fields = [], $as_json = true) {
        if ($this->input->server('REQUEST_METHOD') != 'POST') {
            return $this->_invalid_request($as_json);
        }

        $this->load->library('form_validation');
        $this->load->helper('form');

        foreach ($fields as $field => $rules) {
            if (is_numeric($field)) {
                $this->form_validation->set_rules($rules, 'lang:' . $rules, 'trim|required');
            } else {
                if (is_array($rules)) {
                    $this->form_validation->set_rules($field, 'lang:' . $field, $rules['rules'], $rules['message']);
                } else {
                    $this->form_validation->set_rules($field, 'lang:' . $field, $rules);
                }
            }
        }
        if ($this->form_validation->run() === false) {
            $all_error = [];
            foreach ($fields as $field => $rules) {
                $idx = is_numeric($field) ? $rules : $field;
                $error = form_error($idx, null, null);
                if ($error) {
                    $all_error[$idx] = $error;
                }
            }
            if ($all_error) {
                return $this->_invalid_parameter($all_error, $as_json);
            }
        } else {
            return true;
        }
    }

    protected function post($key, $default = null, $xss_filter = true) {
        return $this->input->post($key, $xss_filter, $default);
    }

    protected function get($key, $default = null, $xss_filter = true) {
        return $this->input->get($key, $xss_filter, $default);
    }

    public function check_all() {
        $action = '_' . $this->post('submit');
        $submit_ids = $this->post('check_all');
        if (!method_exists($this, $action) || !$submit_ids) {
            // show err
            redirect('roles/index');
        }
        $this->$action($submit_ids);
    }

    public function check_all_get() {
        $action = '_' . $this->get('submit');
        $submit_ids = $this->get('check_all');
        if (!method_exists($this, $action) || !$submit_ids) {
            // show err
            redirect('roles/index');
        }
        $this->$action($submit_ids);
    }

    public function get_redir($encode = false) {
        $redir = $this->get('redir', property_exists(get_class(), 'base') ? $this->base : '');
        return $encode ? urlencode($redir) : $redir;
    }

    public function redir($url_default = '', $encode = false) {
        $redir = $this->get('redir', $url_default);
        return $encode ? urlencode($redir) : $redir;
    }

    protected function _show_alert($validate) {
        $message = 'Terjadi Kesalahan:<br />';
        $i = 1;
        foreach ($validate['data'] as $k => $v) {
            $message .= $i . '. ' . $v . '<br />';
            $i++;
        }
        $this->session->set_flashdata('danger', $message);
    }

}
