<?php

use Phalcon\Validation;
use Phalcon\Validation\Validator\Email as EmailValidator;
use Jaga\Traits\ThrowableModel;
use Jaga\Models\UsersSekolah;

/**
 * Class UmUser
 * @property Instansi $Instansi
 */
class UmUser extends \Phalcon\Mvc\Model
{
    use ThrowableModel;

    public static $throwableModelName = 'User';
    public static $pkey = "um_id";

    const SUMBER_KORSUPGAH = 1;
    const SUMBER_IMPORT_CSV = 2;
    const MIGRATION_STATUS_INIT = 0;
    const MIGRATION_STATUS_PASS_CHANGED = 1;

    /**
     *
     * @var integer
     * @Primary
     * @Identity
     *
     */
    public $um_id;

    /**
     *
     * @var string
     */
    public $um_user_name;

    /**
     *
     * @var string
     */
    public $um_user_password;

    /**
     *
     * @var string
     */
    public $um_salt_value;

    /**
     *
     * @var string
     */
    public $um_require_change;

    /**
     *
     * @var string
     */
    public $um_changed_time;

    /**
     *
     * @var integer
     */
    public $um_tenant_id;

    /**
     *
     * @var string
     */
    public $nama;

    /**
     *
     * @var string
     */
    public $tempat_lahir;

    /**
     *
     * @var string
     */
    public $tgl_lahir_old;

    /**
     *
     * @var string
     */
    public $email;

    /**
     *
     * @var string
     */
    public $jenis_kelamin;

    /**
     *
     * @var string
     */
    public $foto;

    /**
     *
     * @var string
     */
    public $is_active;

    /**
     *
     * @var string
     */
    public $phone;

    /**
     *
     * @var string
     */
    public $wso2_id;

    /**
     *
     * @var string
     */
    public $oauth_id;

    /**
     *
     * @var string
     */
    public $twitter_id;

    /**
     *
     * @var string
     */
    public $facebook_id;

    /**
     *
     * @var string
     */
    public $google_id;

    /**
     *
     * @var string
     */
    public $no_ktp_sim;

    /**
     *
     * @var string
     */
    public $uuid_user;

    /**
     *
     * @var string
     */
    public $tgl_lahir;

    /**
     *
     * @var string
     */
    public $is_banned;

    /**
     *
     * @var integer
     */
    public $jmlh_crt_mskn;

    /**
     *
     * @var integer
     */
    public $jmlh_dukung_crt_mskn;

    /**
     *
     * @var string
     */
    public $um_user_new_password;

    /**
     *
     * @var string
     */
    public $apple_id;
    /**
     *
     * @var string
     */
    public $id_sekolah;

    /**
     * @var integer
     */
    public $id_instansi;

    /**
     * @var integer
     */
    public $checkmark_verified;

    public $last_try_login;
    public $try_login;

    /** @var string */
    public $presigned_url;

    /** @var string */
    public $presigned_exp;

    /**
     * @var boolean
     */
    public $is_email_verified;

    /**
     * Validations and business logic
     *
     * @return boolean
     */
    public function validation()
    {
        $validator = new Validation();

        $validator->add(
            'email',
            new EmailValidator(
                [
                    'model' => $this,
                    'message' => 'Please enter a correct email address',
                ]
            )
        );

        return $this->validate($validator);
    }

    /**
     * Initialize method for model.
     */
    public function initialize()
    {
        $this->setSchema("jaga");
        $this->setSource("um_user");
        $this->hasMany('um_id', 'UmUserRole', 'um_user_id');
        $this->hasMany('um_id', 'UsersRoles', 'user_id');
        $this->hasOne('id_jabatan', 'Jabatan', 'id');
        $this->hasOne('id_instansi', 'Instansi', 'id');
        $this->hasManyToMany(
            'um_id',
            'UsersRoles',
            'user_id',
            'role_id',
            'Roles',
            'id',
            [
                'params'   => [
                    'conditions' => '[UsersRoles].deleted_at is NULL'
                ]
            ]
        );
        $this->hasManyToMany(
            'um_id',
            UsersSekolah::class,
            'um_id',
            'sekolah_id',
            'Sekolah',
            'id'
        );
    }

    /**
     * Returns table name mapped in the model.
     *
     * @return string
     */
    public function getSource()
    {
        return 'um_user';
    }

    /**
     * Allows to query a set of records that match the specified conditions
     *
     * @param mixed $parameters
     * @return UmUser[]|UmUser|\Phalcon\Mvc\Model\ResultSetInterface
     */
    public static function find($parameters = null)
    {
        return parent::find($parameters);
    }

    /**
     * Allows to query the first record that match the specified conditions
     *
     * @param mixed $parameters
     * @return UmUser|\Phalcon\Mvc\Model\ResultInterface
     */
    public static function findFirst($parameters = null)
    {
        return parent::findFirst($parameters);
    }

    public static function findFirstByEmail($email)
    {
        return self::findFirst([
            "conditions" => "lower(email) like :email: and is_active = true",
            "bind" => [
                "email" => strtolower($email)
            ]
        ]);
    }

    public function getSequenceName()
    {
        return "jaga.um_user_pk_seq";
    }

    public function getScopes()
    {
        $result = [];

        foreach ($this->roles as $key1 => $role) {
            foreach ($role->scopes as $key2 => $scope) {
                $result[] = $scope->name;
            }
        }

        return $result;
    }

    public function toArray($columns = null)
    {
        $result = parent::toArray($columns);
        $result['roles'] = [];
        $result['instansi'] = empty($this->instansi) ? null : $this->instansi->toSimpleArray(['id', 'nama']);
        $result['sekolah'] = [];
        if (!empty($this->sekolah)) {
            foreach ($this->sekolah as $sch) {
                $result['sekolah'][] = $sch->toSimpleArray();
            }
        }
        foreach ($this->roles as $role) {
            if ($role) {
                $result['roles'][] = $role->toArray(['id', 'name', 'label', 'description']);
            }
        }

        return $result;
    }

    public function baseToArray()
    {
        return $this->toArray(['um_id', 'um_user_name', 'email', 'nama', 'tempat_lahir', 'foto', 'presigned_url', 'presigned_exp', 'phone', 'uuid_user', 'tgl_lahir', 'is_banned', 'jenis_kelamin', 'checkmark_verified']);
    }

    public function toArraySimple()
    {
        return parent::toArray(['um_id', 'um_user_name', 'nama', 'foto', 'uuid_user', 'is_banned', 'jenis_kelamin', 'checkmark_verified']);
    }

    public function toArraySimpleWithFoto()
    {
        return parent::toArray(['um_id', 'um_user_name', 'nama', 'foto', 'presigned_url', 'presigned_exp', 'uuid_user', 'is_banned', 'jenis_kelamin', 'checkmark_verified']);
    }

    public function toArrayForPublicProfile()
    {
        $result = parent::toArray(['um_id', 'um_user_name', 'nama', 'jmlh_dukung_crt_mskn', 'foto', 'presigned_url', 'presigned_exp', 'uuid_user', 'is_banned', 'jenis_kelamin', 'checkmark_verified']);
        $result['jabatan'] = empty($this->jabatan) ? null : $this->jabatan->toArray(['id', 'nama']);
        $result['instansi'] = empty($this->instansi) ? null : $this->instansi->toArray(['id', 'nama']);

        return $result;
    }

    public static function getJabatanFor($id)
    {
        $user = UmUser::findFirst($id);

        if (empty($user)) {
            return null;
        }

        $jabatan = $user->jabatan;

        return empty($jabatan) ? null : $jabatan->toArray();
    }

    public static function getInstansiFor($id)
    {
        $user = UmUser::findFirst($id);

        if (empty($user)) {
            return null;
        }

        $instansi = $user->instansi;

        return empty($instansi) ? null : $instansi->toArray();
    }

    public function setRoles2($roles)
    {
        $current_accesses = UsersRoles::find([
            'conditions' => 'user_id = :user_id:',
            'bind' => ['user_id' => $this->um_id]
        ]);

        foreach ($current_accesses as $key => $current_access) {
            $current_access->delete();
        }

        foreach ($roles as $key => $role) {
            $access = new UsersRoles();
            $access->user_id = $this->um_id;
            $access->role_id = $role->id;
            $access->save();
        }
    }

    public static function getCreationReportBetween($start, $end)
    {
        $sql = "SELECT um_changed_time::date as created_at, count(*) from jaga.um_user where um_changed_time >= :start AND um_changed_time <= :end group by 1 order by 1 asc";

        $user = new UmUser();

        return $user->getReadConnection()->query($sql, [
            'start' => $start,
            'end' => $end
        ])->fetchAll(\PDO::FETCH_ASSOC);
    }

    public function hasRole($roleName)
    {
        if (!empty($this->roles)) {
            $roles = $this->roles;
            foreach ($roles as $key => $role) {
                if ($role->name == $roleName) {
                    return true;
                }
            }
        }

        return false;
    }

    public function isPenggunaOnly(): bool
    {
        $result = true;
        if (!empty($this->roles)) {
            $roles = $this->roles;
            foreach ($roles as $role) {
                if ($role->name != "pengguna") {
                    $result = false;
                }
            }
        }

        return $result;
    }

    public function isRegisBySocmed(): bool{
        if (empty($this->twitter_id) && empty($this->facebook_id) && empty($this->google_id) && empty($this->apple_id)) {
            return false;
        }

        return true;
    }

    /*
     * @param roles integer[] array of role id
     */
    public function syncRoles($roles, $deleteOldRecord = true)
    {
        $currentRoles = UsersRoles::find([
            'conditions' => 'user_id = :user_id:',
            'bind' => ['user_id' => $this->um_id]
        ]);

        $currentRoleIds = [];
        if ($currentRoles->count() > 0) {
            foreach ($currentRoles as $key => $currentRole) {
                $currentRoleIds[] = $currentRole->role_id;
                if ($deleteOldRecord && !in_array($currentRole->role_id, $roles)) {
                    $currentRole->delete();
                }
            }
        }

        foreach ($roles as $key => $newId) {
            if (!in_array($newId, $currentRoleIds)) {

                $newRole = new UsersRoles();
                $newRole->user_id = $this->um_id;
                $newRole->role_id = $newId;
                $save = $newRole->save();
            }
        }
    }

    public function hasNpsn($npsn)
    {
        if (!empty($this->sekolah)) {
            $sekolah = $this->sekolah;
            foreach ($sekolah as $key => $s) {
                if ($s->npsn == $npsn) {
                    return true;
                }
            }
        }

        return false;
    }

    /*
     * @param sekolah String[] array of string npsn
     */
    public function syncSekolahWithNpsn($sekolah,  $deleteOldRecord = true)
    {
        $currentStacks = UsersSekolah::find([
            'conditions' => 'um_id = :um_id:',
            'bind' => ['um_id' => $this->um_id]
        ]);

        $currentStackIds = [];
        if ($currentStacks->count() > 0) {
            foreach ($currentStacks as $key => $currentStack) {

                $currentStackIds[] = $currentStack->sekolah_id;
                if ($deleteOldRecord && !in_array($currentStack->sekolah_id, $sekolah)) {
                    $currentStack->delete();
                }
            }
        }

        if (!empty($sekolah)) {
            foreach ($sekolah as $key => $newId) {
                if (!in_array($newId, $currentStackIds)) {
                    $newRecord = new UsersSekolah();
                    $newRecord->um_id = $this->um_id;
                    $newRecord->npsn = $newId;

                    $sekolah = Sekolah::findFirst("npsn = '" . $newId . "'");
                    $newRecord->sekolah_id = $sekolah->id;

                    $newRecord->save();
                }
            }
        }
    }

    public static function findUserByScopeAndInstansi($scope, $idInstansi) {
        return UmUser::query()
            ->columns('um_id, email')
            ->join('UsersRoles', 'UsersRoles.user_id = UmUser.um_id')
            ->join('RolesScopes', 'RolesScopes.role_id = UsersRoles.role_id')
            ->join('Scopes', 'Scopes.id = RolesScopes.scope_id')
            ->where("Scopes.name ilike :nama_scope: and UmUser.id_instansi = :id_instansi:")
            ->bind(
                [
                    "nama_scope" => $scope,
                    "id_instansi" => $idInstansi
                ]
            )
            ->execute();
    }

    public static function emailsByUmIds(array $ids) {
        $emails = UmUser::query()
            ->columns('email')
            ->where('um_id in (:ids:)')
            ->bind(
                [
                    "ids" => implode(",", $ids)
                ]
            )
            ->execute();
        $result = [];
        foreach ($emails as $email) {
            $result[] = $email->email;
        }
        return $result;
    }
}
