<?php
if(!defined('ABS_PATH')) exit('ABS_PATH is not loaded. Direct access is not allowed.');

/*
 * Copyright 2014 Osclass
 * Copyright 2023 Osclass by OsclassPoint.com
 *
 * Osclass maintained & developed by OsclassPoint.com
 * You may not use this file except in compliance with the License.
 * You may download copy of Osclass at
 *
 *     https://osclass-classifieds.com/download
 *
 * Do not edit or add to this file if you wish to upgrade Osclass to newer
 * versions in the future. Software is distributed on an "AS IS" basis, without
 * warranties or conditions of any kind, either express or implied. Do not remove
 * this NOTICE section as it contains license information and copyrights.
 */


/**
 * Class UserActions
 */
class UserActions {
  public $is_admin;
  public $manager;

  /**
   * UserActions constructor.
   *
   * @param $is_admin
   */
  public function __construct($is_admin) {
    $this->is_admin = $is_admin;
    $this->manager = User::newInstance();
  }

  //add...

  /**
   * @return int
   */
  public function add() {
    $error = array();
    $flash_error = '';
    
    if((osc_recaptcha_enabled() && osc_recaptcha_private_key() != '') && !$this->is_admin && !osc_check_recaptcha()) {
      $flash_error .= _m('The reCAPTCHA was not entered correctly') . PHP_EOL;
      $error[] = 4;
    }

    if(Params::getParam('s_password', false, false) == '') {
      $flash_error .= _m('The password cannot be empty') . PHP_EOL;
      $error[] = 6;
    }

    if(Params::getParam('s_password', false, false) != Params::getParam('s_password2', false, false)) {
      $flash_error .= _m("Passwords don't match") . PHP_EOL;
      $error[] = 7;
    }

    $input = $this->prepareData(true);

    if($input['s_name']=='') {
      $flash_error .= _m('The name cannot be empty') . PHP_EOL;
      $error[] = 10;
    }

    if(!osc_validate_email($input['s_email'])) {
      $flash_error .= _m('The email is not valid') . PHP_EOL;
      $error[] = 5;
    }

    $email_taken = $this->manager->findByEmail($input['s_email']);
    if($email_taken != false) {
      osc_run_hook('register_email_taken', $input['s_email']);
      $flash_error .= _m('The specified e-mail is already in use') . PHP_EOL;
      $error[] = 3;
    }

    if($input['s_username']!='') {
      $username_taken = $this->manager->findByUsername($input['s_username']);
      if(!$error && $username_taken != false) {
        $flash_error .= _m('Username is already taken') . PHP_EOL;
        $error[] = 8;
      }
      if(osc_is_username_blacklisted($input['s_username'])) {
        $flash_error .= _m('The specified username is not valid, it contains some invalid words') . PHP_EOL;
        $error[] = 9;
      }
    }

    $flash_error = osc_apply_filter('user_add_flash_error', $flash_error);
    if($flash_error!='') {
      Session::newInstance()->_setForm('user_s_name', $input['s_name']);
      Session::newInstance()->_setForm('user_s_username', $input['s_username']);
      Session::newInstance()->_setForm('user_s_email', $input['s_email']);
      Session::newInstance()->_setForm('user_s_phone_land', $input['s_phone_land']);
      Session::newInstance()->_setForm('user_s_phone_mobile', $input['s_phone_mobile']);

      osc_run_hook('user_register_failed', $error);
      return $flash_error;
    }

    // hook pre add or edit
    osc_run_hook('pre_user_post');

    $input = osc_apply_filter('user_insert_data', $input);

    $this->manager->insert($input);
    $userId = $this->manager->dao->insertedId();

    if($input['s_username'] == '') {
      if(osc_username_generator() == 'SLUG') {
        $generate_username = osc_sanitize_username($input['s_name']);
        $username_taken = $this->manager->findByUsername($generate_username);
        
        if($username_taken != false) {
          $generate_username .= $userId;
          
          $username_taken = $this->manager->findByUsername($generate_username);
          
          if($username_taken != false) {
            $generate_username = $userId;
          }
        }
        
        if(osc_is_username_blacklisted($generate_username)) {
          $generate_username = $userId;
        }

        $this->manager->update(array('s_username' => $generate_username), array('pk_i_id' => $userId));
      } else {
        $this->manager->update(array('s_username' => $userId), array('pk_i_id' => $userId));
      }
    }

    if(is_array(Params::getParam('s_info'))) {
      $pinfo = (osc_tinymce_users_enabled() == '1' ? Params::getParam('s_info', false, false) : Params::getParam('s_info'));   // update 420
      $pinfo = osc_apply_filter('user_update_description', $pinfo);

      foreach ($pinfo as $key => $value) {
        $this->manager->updateDescription($userId, $key, $value);
      }
    }

    Log::newInstance()->insertLog('user', $this->is_admin ? 'add' : 'register', $userId, $input['s_email'], $this->is_admin ? 'admin' : 'user', $this->is_admin ? osc_logged_admin_id() : $userId);

    $user = $this->manager->findByPrimaryKey($userId);
    if(osc_notify_new_user() && !$this->is_admin) {
      osc_run_hook('hook_email_admin_new_user', $user);
    }

    if(osc_user_validation_enabled() && !$this->is_admin) {
      osc_run_hook('hook_email_user_validation', $user, $input);
      $success = 1;
    } else {
      $this->manager->update(array('b_active' => '1'), array('pk_i_id' => $userId));

      // update items with s_contact_email the same as new user email
      $items_updated = Item::newInstance()->update(array('fk_i_user_id' => $userId, 's_contact_name' => $input['s_name']), array('s_contact_email' => $input['s_email']));
      if($items_updated!==false && $items_updated>0) {
        User::newInstance()->update('i_items = i_items + '. (int)$items_updated, array('pk_i_id' => $userId));
      }
      // update alerts user id with the same email
      Alerts::newInstance()->update(array('fk_i_user_id' => $userId), array('s_email' => $input['s_email']));

      $success = 2;
    }

    osc_run_hook('user_register_completed', $userId);
    return $success;
  }

  //edit...

  /**
   * @param $userId
   *
   * @return int
   */
  public function edit($userId) {
    $input = $this->prepareData(false);

    // hook pre add or edit
    osc_run_hook('pre_user_post');
    $flash_error = '';
    $error = array();
    if($this->is_admin) {
      $user_email = $this->manager->findByEmail($input['s_email']);
      if(isset($user_email['pk_i_id']) && $user_email['pk_i_id'] != $userId) {
        $flash_error .= sprintf(_m('The specified e-mail is already used by %s'), $user_email['s_username']) . PHP_EOL;
        $error[] = 3;
      }
    }

    if($input['s_name']=='') {
      $flash_error .= _m('The name cannot be empty').PHP_EOL;
      $error[] = 10;
    }

    if($this->is_admin){
      if(Params::getParam('s_password', false, false) != Params::getParam('s_password2', false, false)) {
        $flash_error .= _m("Passwords don't match") . PHP_EOL;
        $error[] = 7;
      }
    }

    $flash_error = osc_apply_filter('user_edit_flash_error', $flash_error, $userId);
    if($flash_error!='') {
      return $flash_error;
    }

    $input = osc_apply_filter('user_edit_data', $input);

    $this->manager->update($input, array('pk_i_id' => $userId));

    if($this->is_admin) {
      Item::newInstance()->update(array('s_contact_name' => $input['s_name'], 's_contact_email' => $input['s_email']), array('fk_i_user_id' => $userId));
      ItemComment::newInstance()->update(array('s_author_name' => $input['s_name'], 's_author_email' => $input['s_email']), array('fk_i_user_id' => $userId));
      Alerts::newInstance()->update(array('s_email' => $input['s_email']), array('fk_i_user_id' => $userId));

      Log::newInstance()->insertLog('user', 'edit', $userId, $input['s_email'], $this->is_admin ? 'admin' : 'user', $this->is_admin ? osc_logged_admin_id() : osc_logged_user_id());
    } else {
      Item::newInstance()->update(array('s_contact_name' => $input['s_name']), array('fk_i_user_id' => $userId));
      ItemComment::newInstance()->update(array('s_author_name' => $input['s_name']), array('fk_i_user_id' => $userId));
      $user = $this->manager->findByPrimaryKey($userId);

      Log::newInstance()->insertLog('user', 'edit', $userId, $user['s_email'], $this->is_admin ? 'admin' : 'user', $this->is_admin ? osc_logged_admin_id() : osc_logged_user_id());
    }

    if(!$this->is_admin) {
      Session::newInstance()->_set('userName', $input['s_name']);
      $phone = $input['s_phone_mobile'] ?: $input['s_phone_land'];
      Session::newInstance()->_set('userPhone', $phone);
    }

    if(is_array(Params::getParam('s_info'))) {
      $pinfo = (osc_tinymce_users_enabled() == '1' ? Params::getParam('s_info', false, false) : Params::getParam('s_info'));   // update 420
      
      foreach ($pinfo as $key => $value) {
        $this->manager->updateDescription($userId, $key, $value);
      }
    }

    osc_run_hook('user_edit_completed', $userId);

    if($this->is_admin) {
      $iUpdated = 0;
      if((Params::getParam('b_enabled') != '') && (Params::getParam('b_enabled') == 1)) {
        $iUpdated += $this->manager->update(array('b_enabled' => 1), array('pk_i_id' => $userId));
      } else {
        $iUpdated += $this->manager->update(array('b_enabled' => 0), array('pk_i_id' => $userId));
      }

      if((Params::getParam('b_active') != '') && (Params::getParam('b_active') == 1)) {
        $iUpdated += $this->manager->update(array('b_active' => 1), array('pk_i_id' => $userId));
      } else {
        $iUpdated += $this->manager->update(array('b_active' => 0), array('pk_i_id' => $userId));
      }

      if($iUpdated > 0) {
        return 2;
      }
    }

    return 1;
  }

  /**
   * @return int
   */
  public function recover_password() {
    $user = User::newInstance()->findByEmail(Params::getParam('s_email'));
    Session::newInstance()->_set('recover_time', time());

    if((osc_recaptcha_enabled() && osc_recaptcha_private_key() != '') && Session::newInstance()->_get('recover_captcha_not_set') != 1 && !osc_check_recaptcha()) {
      return 2; // BREAK THE PROCESS, THE RECAPTCHA IS WRONG
    }

    if(!$user || ($user['b_enabled'] == 0)) {
      return 1;
    }

    $code = osc_genRandomPassword(30);
    $date = date('Y-m-d H:i:s');
    
    User::newInstance()->update(
      array('s_pass_code' => $code, 's_pass_date' => $date, 's_pass_ip' => osc_get_ip()),
      array('pk_i_id' => $user['pk_i_id'])
   );

    $password_url = osc_forgot_user_password_confirm_url($user['pk_i_id'], $code);
    osc_run_hook('hook_email_user_forgot_password', $user, $password_url);

    return 0;
  }

  /**
   * @param $is_add
   *
   * @return array
   */
  public function prepareData($is_add) {
    $input = array();

    if($is_add) {
      $date = date('Y-m-d H:i:s');
      $input['dt_reg_date'] = $date;
      $input['dt_mod_date'] = $date;
      $input['dt_access_date'] = $date;
      $input['s_secret'] = osc_genRandomPassword();
      $input['s_access_ip'] = osc_get_ip(); //Params::getServerParam('REMOTE_ADDR');
    } else {
      $input['dt_mod_date'] = date('Y-m-d H:i:s');
    }

    //only for administration, in the public website this two params are edited separately
    if($this->is_admin || $is_add) {
      $input['s_email'] = Params::getParam('s_email');

      //if we want to change the password
      if(Params::getParam('s_password', false, false) != '') {
        $input['s_password'] = osc_hash_password(Params::getParam('s_password', false, false));
      }
      
      $input['s_username'] = osc_sanitize_username(Params::getParam('s_username'));
    }

    $input['s_name'] = trim(Params::getParam('s_name'));
    $input['s_website'] = trim(Params::getParam('s_website'));
    $input['s_phone_land'] = trim(Params::getParam('s_phone_land'));
    $input['s_phone_mobile'] = trim(Params::getParam('s_phone_mobile'));

    if(stripos($input['s_website'], 'http') !== 0) {
      $input['s_website'] = 'http://'.$input['s_website'];
    }
    
    $input['s_website'] = osc_sanitize_url($input['s_website']);

    if(osc_validate_url($input['s_website']) === false) {   // url is not valid, update 321
      $input['s_website'] = '';
    }

    //locations...
    $country = Country::newInstance()->findByCode(Params::getParam('countryId'));

    if(!isset($country['pk_c_code'])) {
      $country = Country::newInstance()->findByName(Params::getParam('country'));
    }
    
    if(isset($country['pk_c_code'])) {
      $countryId = $country['pk_c_code'];
      $countryName = $country['s_name'];
      $countryNameNative = $country['s_name_native'];
    } else {
      $countryId = null;
      $countryName = Params::getParam('country');
      $countryNameNative = null;
    }

    if((int)Params::getParam('regionId') > 0) {
      $region = Region::newInstance()->findByPrimaryKey(Params::getParam('regionId'));
    } else {
      $region = Region::newInstance()->findByName(Params::getParam('region'), Params::getParam('countryId'));
    }

    if(isset($region['pk_i_id'])) {
      $regionId = $region['pk_i_id'];
      $regionName = $region['s_name'];
      $regionNameNative = $region['s_name_native'];
    } else {
      $regionId = null;
      $regionName = Params::getParam('region');
      $regionNameNative = null;
    }

    if((int)Params::getParam('cityId') > 0) {
      $city = City::newInstance()->findByPrimaryKey(Params::getParam('cityId'));
    } else {
      $city = City::newInstance()->findByName(Params::getParam('city'), Params::getParam('regionId'));
    }

    if(isset($city['pk_i_id'])) {
      $cityId = $city['pk_i_id'];
      $cityName = $city['s_name'];
      $cityNameNative = $city['s_name_native'];
    } else {
      $cityId = null;
      $cityName = Params::getParam('city');
      $cityNameNative = null;
    }

    $input['fk_c_country_code'] = $countryId;
    $input['s_country'] = $countryName;
    $input['s_country_native'] = $countryNameNative;
    $input['fk_i_region_id'] = $regionId;
    $input['s_region'] = $regionName;
    $input['s_region_native'] = $regionNameNative;
    $input['fk_i_city_id'] = $cityId;
    $input['s_city'] = $cityName;
    $input['s_city_native'] = $cityNameNative;
    $input['s_city_area'] = Params::getParam('cityArea');
    $input['s_address'] = Params::getParam('address');
    $input['s_zip'] = Params::getParam('zip');
    $input['d_coord_lat'] = (Params::getParam('d_coord_lat')  != '') ? Params::getParam('d_coord_lat') : @$city['d_coord_lat'];   // maybe $city['d_coord_lat'] does not exists
    $input['d_coord_long'] = (Params::getParam('d_coord_long') != '') ? Params::getParam('d_coord_long') : @$city['d_coord_long'];
    $input['b_company'] = (Params::getParam('b_company') != '' && Params::getParam('b_company') != 0) ? 1 : 0;

    return $input;
  }

  /**
   * @param $user_id
   *
   * @return bool
   * @throws \Exception
   */
  public function activate($user_id) {
    $user = $this->manager->findByPrimaryKey($user_id);

    if(!$user) {
      return false;
    }

    $this->manager->update(array('b_active' => 1), array('pk_i_id' => $user_id));

    if(!$this->is_admin) {
      osc_run_hook('hook_email_admin_new_user', $user);
    }

    Log::newInstance()->insertLog('user', 'activate', $user_id, $user['s_email'], $this->is_admin ? 'admin' : 'user', $this->is_admin ? osc_logged_admin_id() : osc_logged_user_id());

    if($user['b_enabled'] == 1) {
      $mItem = new ItemActions(true);
      $items = Item::newInstance()->findByUserID($user_id);
      foreach($items as $item) {
        $mItem->enable($item['pk_i_id']);
      }
    }

    // update items with s_contact_email the same as new user email
    $items_updated = Item::newInstance()->update(array('fk_i_user_id' => $user_id, 's_contact_name' => $user['s_name']), array('s_contact_email' => $user['s_email']));
    if($items_updated!==false && $items_updated>0) {
      User::newInstance()->update('i_items = i_items + '. (int)$items_updated, array('pk_i_id' => $user_id));
    }
    // update alerts user id with the same email
    Alerts::newInstance()->update(array('fk_i_user_id' => $user_id), array('s_email' => $user['s_email']));

    osc_run_hook('activate_user', $user);

    return true;
  }

  /**
   * @param $user_id
   *
   * @return bool
   * @throws \Exception
   */
  public function deactivate($user_id) {
    $user = $this->manager->findByPrimaryKey($user_id);

    if(!$user) {
      return false;
    }

    $this->manager->update(array('b_active' => 0), array('pk_i_id' => $user_id));

    Log::newInstance()->insertLog('user', 'deactivate', $user_id, $user['s_email'], $this->is_admin ? 'admin' : 'user', $this->is_admin ? osc_logged_admin_id() : osc_logged_user_id());

    if($user['b_enabled'] == 1) {
      $mItem = new ItemActions(true);
      $items = Item::newInstance()->findByUserID($user_id);
      foreach($items as $item) {
        $mItem->disable($item['pk_i_id']);
      }
    }
    osc_run_hook('deactivate_user', $user);

    return true;
  }

  /**
   * @param $user_id
   *
   * @return bool
   * @throws \Exception
   */
  public function enable($user_id) {
    $user = $this->manager->findByPrimaryKey($user_id);

    if(!$user) {
      return false;
    }

    $this->manager->update(array('b_enabled' => 1), array('pk_i_id' => $user_id));

    Log::newInstance()->insertLog('user', 'enable', $user_id, $user['s_email'], $this->is_admin ? 'admin' : 'user', $this->is_admin ? osc_logged_admin_id() : osc_logged_user_id());

    if($user['b_active'] == 1) {
      $mItem = new ItemActions(true);
      $items = Item::newInstance()->findByUserID($user_id);
      foreach($items as $item) {
        $mItem->enable($item['pk_i_id']);
      }
    }
    osc_run_hook('enable_user', $user);

    return true;
  }

  /**
   * @param $user_id
   *
   * @return bool
   * @throws \Exception
   */
  public function disable($user_id) {
    $user = $this->manager->findByPrimaryKey($user_id);

    if(!$user) {
      return false;
    }

    $this->manager->update(array('b_enabled' => 0), array('pk_i_id' => $user_id));

    Log::newInstance()->insertLog('user', 'disable', $user_id, $user['s_email'], $this->is_admin ? 'admin' : 'user', $this->is_admin ? osc_logged_admin_id() : osc_logged_user_id());

    if($user['b_active'] == 1) {
      $mItem = new ItemActions(true);
      $items = Item::newInstance()->findByUserID($user_id);
      foreach($items as $item) {
        $mItem->disable($item['pk_i_id']);
      }
    }
    osc_run_hook('disable_user', $user);

    return true;
  }

  /**
   * @param $user_id
   *
   * @return int
   */
  public function resend_activation($user_id) {
    $user = $this->manager->findByPrimaryKey($user_id);
    $input['s_secret'] = $user['s_secret'];

    if(!$user  || $user['b_active']==1) {
      return 0;
    }

    if(osc_user_validation_enabled()) {
      osc_run_hook('hook_email_user_validation', $user, $input);
      return 1;
    }

    return 0;
  }

  /**
   * @param $user_id
   *
   * @return int
   */
  public function bootstrap_login($user_id) {
    $user = User::newInstance()->findByPrimaryKey($user_id);

    if(!$user) {
      return 0;
    }

    if(!$user['b_active']) {
      return 1;
    }

    if(!$user['b_enabled']) {
      return 2;
    }

    //we are logged in... let's go!
    Session::newInstance()->_set('userId', $user['pk_i_id']);
    Session::newInstance()->_set('userName', $user['s_name']);
    Session::newInstance()->_set('userEmail', $user['s_email']);
    $phone = $user['s_phone_mobile'] ?: $user['s_phone_land'];
    Session::newInstance()->_set('userPhone', $phone);

    return 3;
  }
}