<?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');

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

    const STATUS_ACTIVE = 1;
    const STATUS_BANNED = 2;
    // login type (please define too at Role_model for CMS)
    const LOGIN_TYPE_BACKOFFICE = 1;
    const LOGIN_TYPE_PUBLIC = 2;
    const LOGIN_TYPE_VISITOR = 3;
    // doorprize
    const DOORPRIZE_YES = 1;
    const DOORPRIZE_NO = 2;
    // USER MANAGEMENT LIST
    const ACCESS_PERMISSION_LIST = 'Permission List';
    const ACCESS_PERMISSION_CREATE = 'Permission Create';
    const ACCESS_PERMISSION_UPDATE = 'Permission Update';
    const ACCESS_PERMISSION_DELETE = 'Permission Delete';
    const ACCESS_ROLE_LIST = 'Role List';
    const ACCESS_ROLE_CREATE = 'Role Create';
    const ACCESS_ROLE_UPDATE = 'Role Update';
    const ACCESS_ROLE_DELETE = 'Role Delete';
    const ACCESS_USER_LIST = 'User List';
    const ACCESS_USER_CREATE = 'User Create';
    const ACCESS_USER_UPDATE = 'User Update';
    const ACCESS_USER_DELETE = 'User Delete';
    const ACCESS_PUBLIC_USER_LIST = 'Public User List'; // public user & public user log
    const ACCESS_PUBLIC_USER_CREATE = 'Public User Create';
    const ACCESS_PUBLIC_USER_UPDATE = 'Public User Update';
    const ACCESS_PUBLIC_USER_DELETE = 'Public User Delete';
    const ACCESS_VISITOR_USER_LIST = 'Visitor User List'; // Visitor User
    const ACCESS_VISITOR_USER_CREATE = 'Visitor User Create';
    const ACCESS_VISITOR_USER_UPDATE = 'Visitor User Update';
    const ACCESS_VISITOR_USER_DELETE = 'Visitor User Delete';
    // CONFIG PERMISSION LIST 
    const ACCESS_CONFIG_LIST = 'Config List';
    const ACCESS_CONFIG_CREATE = 'Config Create';
    const ACCESS_CONFIG_UPDATE = 'Config Update';
    const ACCESS_CONFIG_DELETE = 'Config Delete';
    // ABSEN PERMISSION LIST
    const ACCESS_ABSEN_LIST = 'Absen List';
    const ACCESS_ABSEN_CREATE = 'Absen Create';
    const ACCESS_ABSEN_UPDATE = 'Absen Update';
    const ACCESS_ABSEN_DELETE = 'Absen Delete';
    const ACCESS_ABSEN_QR = 'Absen QR';
    const ACCESS_ABSEN_QR_LIST = 'Absen QR List';

    protected $table = "users";
    public $timestamps = true;

    public function __construct(array $attributes = array()) {
        parent::__construct($attributes);
    }

//    public static $relation_list = [
//        "roles" => Role_model::class,
//        "profile" => User_profile_model::class,
//    ];

    public static function status_label($selected = null) {
        $lib = [
            self::STATUS_ACTIVE => lang('ACTIVE'),
            self::STATUS_BANNED => lang('BANNED'),
        ];
        return array_key_exists($selected, $lib) ? $lib[$selected] : $lib;
    }

    public static function permission_group_access() {
        return [
            1 => [
                'group' => 'Permission',
                'name' => self::ACCESS_PERMISSION_LIST,
                'desc' => '',
            ],
            2 => [
                'group' => 'Permission',
                'name' => self::ACCESS_PERMISSION_CREATE,
                'desc' => '',
            ],
            3 => [
                'group' => 'Permission',
                'name' => self::ACCESS_PERMISSION_UPDATE,
                'desc' => '',
            ],
            4 => [
                'group' => 'Permission',
                'name' => self::ACCESS_PERMISSION_DELETE,
                'desc' => '',
            ],
        ];
    }

    public static function role_group_access() {
        return [
            5 => [
                'group' => 'Role',
                'name' => self::ACCESS_ROLE_LIST,
                'desc' => '',
            ],
            6 => [
                'group' => 'Role',
                'name' => self::ACCESS_ROLE_CREATE,
                'desc' => '',
            ],
            7 => [
                'group' => 'Role',
                'name' => self::ACCESS_ROLE_UPDATE,
                'desc' => '',
            ],
            8 => [
                'group' => 'Role',
                'name' => self::ACCESS_ROLE_DELETE,
                'desc' => '',
            ],
        ];
    }

    public static function user_group_access() {
        return [
            9 => [
                'group' => 'User',
                'name' => self::ACCESS_USER_LIST,
                'desc' => '',
            ],
            10 => [
                'group' => 'User',
                'name' => self::ACCESS_USER_CREATE,
                'desc' => '',
            ],
            11 => [
                'group' => 'User',
                'name' => self::ACCESS_USER_UPDATE,
                'desc' => '',
            ],
            12 => [
                'group' => 'User',
                'name' => self::ACCESS_USER_DELETE,
                'desc' => '',
            ],
        ];
    }

    public static function public_user_group_access() {
        return [
            13 => [
                'group' => 'Public User',
                'name' => self::ACCESS_PUBLIC_USER_LIST,
                'desc' => 'Public User & Public User Log',
            ],
            14 => [
                'group' => 'Public User',
                'name' => self::ACCESS_PUBLIC_USER_CREATE,
                'desc' => 'Public User & Public User Log',
            ],
            15 => [
                'group' => 'Public User',
                'name' => self::ACCESS_PUBLIC_USER_UPDATE,
                'desc' => 'Public User & Public User Log',
            ],
            16 => [
                'group' => 'Public User',
                'name' => self::ACCESS_PUBLIC_USER_DELETE,
                'desc' => 'Public User & Public User Log',
            ],
        ];
    }

    public static function visitor_user_group_access() {
        return [
            17 => [
                'group' => 'Visitor User',
                'name' => self::ACCESS_VISITOR_USER_LIST,
                'desc' => 'Visitor User',
            ],
            18 => [
                'group' => 'Visitor User',
                'name' => self::ACCESS_VISITOR_USER_CREATE,
                'desc' => 'Visitor User',
            ],
            19 => [
                'group' => 'Visitor User',
                'name' => self::ACCESS_VISITOR_USER_UPDATE,
                'desc' => 'Visitor User',
            ],
            20 => [
                'group' => 'Visitor User',
                'name' => self::ACCESS_VISITOR_USER_DELETE,
                'desc' => 'Visitor User',
            ],
        ];
    }

    public static function config_group_access() {
        return [
            21 => [
                'group' => 'Config',
                'name' => self::ACCESS_CONFIG_LIST,
                'desc' => '',
            ],
            22 => [
                'group' => 'Config',
                'name' => self::ACCESS_CONFIG_CREATE,
                'desc' => '',
            ],
            23 => [
                'group' => 'Config',
                'name' => self::ACCESS_CONFIG_UPDATE,
                'desc' => '',
            ],
            24 => [
                'group' => 'Config',
                'name' => self::ACCESS_CONFIG_DELETE,
                'desc' => '',
            ],
        ];
    }

    public static function absen_group_access() {
        return [
            25 => [
                'group' => 'Absen',
                'name' => self::ACCESS_ABSEN_LIST,
                'desc' => '',
            ],
            26 => [
                'group' => 'Absen',
                'name' => self::ACCESS_ABSEN_CREATE,
                'desc' => '',
            ],
            27 => [
                'group' => 'Absen',
                'name' => self::ACCESS_ABSEN_UPDATE,
                'desc' => '',
            ],
            28 => [
                'group' => 'Absen',
                'name' => self::ACCESS_ABSEN_DELETE,
                'desc' => '',
            ],
            29 => [
                'group' => 'Absen',
                'name' => self::ACCESS_ABSEN_QR,
                'desc' => '',
            ],
            30 => [
                'group' => 'Absen',
                'name' => self::ACCESS_ABSEN_QR_LIST,
                'desc' => '',
            ],
        ];
    }

    public static function permission_list() {
        $all_permission_list = self::permission_group_access() +
            self::role_group_access() +
            self::user_group_access() +
            self::public_user_group_access() +
            self::visitor_user_group_access() +
            self::config_group_access() +
            self::absen_group_access();

        return $all_permission_list;
    }

    /**
     * Get related roles
     * 
     * @return Object Role_model 
     */
    public function roles() {
        return $this->belongsToMany(Role_model::class, 'user_roles', 'user_id', 'role_id');
    }

    /**
     * Get related user_profile
     *  
     * @return Object User_role_model 
     */
    public function profile() {
        return $this->hasOne(User_profile_model::class, 'user_id');
    }

    public function notification() {
        return $this->hasMany(User_notification_model::class, 'toid', 'id');
    }

    public function get_permissions() {

        $collector = collect(new Permission_model);
        if ($this->roles) {
            foreach ($this->roles as $role) {
                if (!$role->permissions) {
                    continue;
                }
                foreach ($role->permissions as $permission) {
                    if (!$collector->has($permission->id)) {
                        $collector->add($permission);
                    }
                }
            }
        }
        return $collector;
    }

    public function get_by_role($role_id = null, $except = []) {
        $query = static::get_dbo($this->table)
            ->select($this->table . '.*')
            ->join('user_roles', 'users.id', '=', 'user_roles.user_id', 'left')
            ->where('user_roles.role_id', $role_id);
        if ($except) {
            $query->whereNotIn($this->table . '.id', $except);
        }
        return $query->get();
    }

    public static function get_dropdown_by_role($role_id, $except = []) {
        $query = static::get_dbo('users')
            ->select('users.*')
            ->join('user_roles', 'users.id', '=', 'user_roles.user_id', 'left')
            ->where('user_roles.role_id', $role_id);
        if ($except) {
            $query->whereNotIn('users.id', $except);
        }
        $model = $query->get();
        $return = [];
        if ($model->count() > 0) {
            foreach ($model as $res) {
                $return[$res->id] = $res->profile->name;
            }
        }
        return $return;
    }

    public function login($data, $type_login) {
        $CI = & get_instance();
        $CI->load->helper('hash');
        $user = static::get_dbo()->where('username', $data['username'])->first();
        if (!$user) {
            return [
                'status' => 2,
                'message' => lang('user_not_found')
            ];
        }
        if (!run_verify($data['password'], $user->password)) {
            return [
                'status' => 2,
                'message' => lang('password_incorrect')
            ];
        }
        if ($user->status == self::STATUS_BANNED) {
            return [
                'status' => 2,
                'message' => lang('account_banned')
            ];
        }
        $can_login = false;
        $login_types = $user->roles->pluck('login_type')->toArray();
        foreach ($login_types as $type) {
            if ($type_login == $type) {
                $can_login = true;
            }
        }
        if ($can_login === false) {
            return [
                'status' => 2,
                'message' => lang('permission_denied')
            ];
        }
        $token = $user->login_token ? $user->login_token : md5(time());
        $session = [
            'user' => $user->toArray(),
            'profile' => $user->profile->toArray(),
            'permissions' => $user->get_permissions()->pluck('name', 'id')->toArray(),
            'token' => $token,
            'login_types' => $login_types
        ];
        $directory = $CI->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;
        } else {
            $token_session = TOKEN_SESSION;
            $token_cookie = TOKEN_COOKIE;
        }
        $user->login_token = $token;
        $user->save();
        $CI->session->set_userdata($token_session, $session);
        if ($data['rememberme'] == 'yes') {
            setcookie($token_cookie, $token, strtotime("+30 days", time()), '/');
        }
        return [
            'status' => 1,
            'user' => $user
        ];
    }

    public function logout($id) {
        $CI = & get_instance();
        $user = static::get_dbo()->where('id', $id)->first();
        if ($user) {
            $user->login_token = null;
            $user->save();
        }
        $directory = $CI->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;
        } else {
            $token_session = TOKEN_SESSION;
            $token_cookie = TOKEN_COOKIE;
        }

        $CI->session->unset_userdata($token_session);
        setcookie($token_cookie, '', time() - 3600, base_url());
    }

    public static function generate_identity($id) {
        $CI = & get_instance();
        $CI->load->helper('string');
        $mask1 = random_string('numeric', 3);
        $mask2 = random_string('numeric', 3);
        $mask3 = strlen($id) < 3 ? substr('000' . $id, -3, 3) : $id;
        return $mask1 . $mask3 . $mask2;
    }

}
