<?php
namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\Auth\DefaultPasswordHasher;
use Cake\Utility\Security;

class UsersTable extends Table
{
	public function initialize(array $config): void
	{
		parent::initialize($config);
		$this->setTable('user');
		$this->setEntityClass('App\Model\Entity\User');
		$this->hasMany('Videos', [
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasMany('Notifications', [
			'className' => 'Notifications',
			'foreignKey' => 'receiver_id',
			'dependent' => true
		]);
		$this->hasMany('VideoLikes', [
			'className' => 'VideoLikes',
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasMany('VideoComments', [
			'className' => 'VideoComments',
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasMany('VideoCommentLikes', [
			'className' => 'VideoCommentLikes',
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasMany('VideoFavourites', [
			'className' => 'VideoFavourites',
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasMany('Followers', [
			'className' => 'Followers',
			'foreignKey' => 'receiver_id',
			'dependent' => true
		]);
		$this->hasMany('Playlists', [
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasMany('Cards', [
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasMany('DeliveryAddresses', [
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasMany('Orders', [
			'foreignKey' => 'user_id',
			'dependent' => true
		]);
		$this->hasOne('PushNotifications', [
			'foreignKey' => 'id',
			'dependent' => true
		]);
		$this->hasOne('PrivacySettings', [
			'foreignKey' => 'id',
			'dependent' => true
		]);
	}

	public function isEmailAlreadyExist(string $email): int
	{
		return $this->find()->where(['email' => $email])->count();
	}

	public function getUsersWhoHasProfilePic($starting_point)
	{
		return $this->find()
			->where(['profile_pic !=' => '', 'id' => 3])
			->limit(5)
			->all();
	}

	public function isfbAlreadyExist($fb_id): int
	{
		return $this->find()->where(['fb_id' => $fb_id])->count();
	}

	public function getDetailsAgainstAuthToken($auth_token)
	{
		return $this->find()
			->where(['auth_token' => $auth_token])
			->first();
	}

	public function getUserDetailsAgainstAuthToken($auth_token)
	{
		return $this->find()
			->where(['auth_token' => $auth_token])
			->first();
	}

	public function getBusinessUsers($starting_point)
	{
		return $this->find()
			->select(USER_FIELDS)
			->where(['business' => 1])
			->limit(10)
			->offset($starting_point * 10)
			->all();
	}

	public function getAllFacebookUsers(array $fb_ids, $user_id)
	{
		return $this->find()
			->where(['social_id IN' => $fb_ids, 'social' => 'facebook', 'id !=' => $user_id])
			->all();
	}

	public function isSocialIDAlreadyExist($social_id)
	{
		return $this->find()->where(['social_id' => $social_id])->first();
	}

	public function isSocialIDAlreadyExistAgainstType($email, $social_id)
	{
		return $this->find()->where(['social_id' => $social_id, 'email' => $email])->first();
	}

	public function verifyToken($code, $email): int
	{
		return $this->find()->where(['email' => $email, 'token' => $code])->count();
	}

	public function getUserDetailsAgainstEmail($email)
	{
		return $this->find()->where(['email' => $email])->first();
	}

	public function getUserDetailsAgainstEmailCount($email): int
	{
		return $this->find()->where(['email' => $email])->count();
	}

	public function getUserDetailsAgainstUsername($username)
	{
		return $this->find()->where(['username' => $username])->first();
	}

	public function getDetailsAgainstReferral($referral_code)
	{
		return $this->find()->where(['referral_code' => $referral_code])->first();
	}

	public function isUsernameAlreadyExist($username): int
	{
		return $this->find()->where(['username' => $username])->count();
	}

	public function getRecommendedRandomUsers($business)
	{
		return $this->find()
			->where(['first_name !=' => '', 'last_name !=' => '', 'business' => $business, 'profile_pic !=' => ''])
			->order('rand()')
			->limit(10)
			->all();
	}

	public function getRecommendedUsers($user_id, $followers, $business, $starting_point)
	{
		return $this->find()
			->where(['id !=' => $user_id, 'business' => $business, 'profile_pic !=' => '', 'id NOT IN' => $followers])
			->order('rand()')
			->limit(10)
			->offset($starting_point * 10)
			->all();
	}

	public function isphoneNoAlreadyExist($phone): int
	{
		return $this->find()->where(['phone' => $phone])->count();
	}

	public function isPhoneAlreadyExistAgainstType($type, $phone)
	{
		return $this->find()->where(['phone' => $phone, 'social' => $type])->first();
	}

	public function editIsEmailAlreadyExist($email, $user_id): int
	{
		return $this->find()->where(['email' => $email, 'id !=' => $user_id])->count();
	}

	public function editIsUsernameAlreadyExist($username, $user_id): int
	{
		return $this->find()->where(['username' => $username, 'id !=' => $user_id])->count();
	}

	public function editIsphoneNoAlreadyExist($phone, $user_id): int
	{
		return $this->find()->where(['phone' => $phone, 'id !=' => $user_id])->count();
	}

	public function iSUserExist($id): int
	{
		return $this->find()->where(['id' => $id])->count();
	}

	public function getMultipleUsersData(array $users)
	{
		return $this->find()->where(['id IN' => $users])->all();
	}

	public function getUsersCount($role): int
	{
		return $this->find()->where(['role' => $role])->count();
	}

	public function getTotalUsersCount(): int
	{
		return $this->find()->count();
	}

	public function getObjectsForCache($id)
	{
		return $this->find()
			->contain(['PrivacySettings', 'PushNotifications'])
			->select([
				'id', 'first_name', 'last_name', 'bio', 'website', 'profile_pic',
				'profile_pic_small', 'profile_gif', 'device_token', 'business',
				'parent', 'username', 'device_token', 'verified'
			])
			->where(['id' => $id])
			->first();
	}

	public function getUserDetailsFromID($user_id)
	{
		return $this->find()
			->contain([
				'PushNotifications',
				'PrivacySettings',
				'DeliveryAddresses' => function ($q) {
					return $q->where(['DeliveryAddresses.default' => 1])->limit(1);
				},
				'Cards' => function ($q) {
					return $q->where(['Cards.default' => 1])->limit(1);
				}
			])
			->where(['id' => $user_id, 'active' => 1])
			->first();
	}

	public function getUserDetailsFromIDContain($user_id)
	{
		return $this->find()->where(['id' => $user_id])->first();
	}

	public function getOnlyUserDetailsFromID($user_id)
	{
		return $this->find()->where(['id' => $user_id, 'active' => 1])->first();
	}

	public function getUserDetailsFromUsername($username)
	{
		return $this->find()->where(['username' => $username])->first();
	}

	public function getUserDetailsFromIDAndRole($user_id, $role)
	{
		return $this->find()->where(['id' => $user_id, 'role' => $role])->first();
	}

	public function getDriverDetails($user_id, $role)
	{
		return $this->find()
			->contain(['Vehicles.RideTypes', 'DriverDocuments'])
			->where(['id' => $user_id, 'role' => $role])
			->first();
	}

	public function getSearchResultsAgainstType($keyword, $starting_point, $type)
	{
		if ($type === "username") {
			$condition = ['username LIKE' => $keyword . '%'];
		} elseif ($type === "email") {
			$condition = ['email LIKE' => $keyword . '%'];
		} elseif ($type === "name") {
			$condition = ['OR' => [['first_name LIKE' => $keyword . '%'], ['last_name LIKE' => $keyword . '%']]];
		} else {
			$condition = [];
		}
		return $this->find()
			->where($condition)
			->limit(10)
			->offset($starting_point * 10)
			->order(['id' => 'ASC'])
			->all();
	}

	public function getSearchResults($keyword, $starting_point, $user_id, $type)
	{
		$condition = [
			'OR' => [
				['username LIKE' => $keyword . '%'],
				['first_name LIKE' => $keyword . '%'],
				['last_name LIKE' => $keyword . '%']
			],
			'id !=' => $user_id
		];
		return $this->find()
			->select(USER_FIELDS)
			->where($condition)
			->limit(10)
			->offset($starting_point * 10)
			->order(['id' => 'ASC'])
			->all();
	}

	public function verifyPassword($email, $old_password): bool
	{
		$user = $this->find()->select(['id', 'password'])->where(['email' => $email])->first();
		if (!$user) {
			return false;
		}
		$hasher = new DefaultPasswordHasher();
		return $hasher->check($old_password, $user->password);
	}

	public function updatepassword($password)
	{
		$hasher = new DefaultPasswordHasher();
		return ['password' => $hasher->hash($password)];
	}

	public function getEmailBasedOnUserID($user_id)
	{
		return $this->find()->where(['id' => $user_id])->all();
	}

	public function testAllUser()
	{
		return $this->find()->where(['business IN' => [0, 2], 'auth_token !=' => ''])->all();
	}

	public function getAllUsersNonBusiness()
	{
		return $this->find()
			->leftJoinWith('UserInterests')
			->where(['business' => 0, 'UserInterests.user_id IS' => null])
			->order(['id' => 'DESC'])
			->all();
	}

	public function getAllUsers($business, $starting_point)
	{
		$condition = $business < 1 ? ['business' => $business] : ['business >' => 0];
		return $this->find()
			->where($condition)
			->limit(20)
			->offset($starting_point * 20)
			->order(['id' => 'DESC'])
			->all();
	}

	public function getAllUsersNotification()
	{
		return $this->find()->order(['id' => 'DESC'])->all();
	}

	public function getAllUsersAgainstUserIDs(array $user_ids)
	{
		return $this->find()->where(['id IN' => $user_ids])->all();
	}

	public function getDistinctCountries()
	{
		return $this->find()
			->select(['country'])
			->where(['country !=' => ''])
			->group('country')
			->all();
	}

	public function searchLocation($keyword)
	{
		$conn = $this->getConnection();
		return $conn->execute("SELECT DISTINCT country, city, region FROM user WHERE country LIKE '$keyword%' OR city LIKE '$keyword%' OR region LIKE '$keyword%'")->fetchAll('assoc');
	}

	public function searchLocation2($keyword)
	{
		return $this->find()
			->select(['country', 'city'])
			->where([
				'OR' => [
					['country LIKE' => $keyword . '%'],
					['city LIKE' => $keyword . '%'],
					['region LIKE' => $keyword . '%']
				],
				'country !=' => ''
			])
			->group(['country', 'city'])
			->all();
	}

	public function totalAudienceAgainstGenderAndCountry($min_age, $max_age, $gender, $country_id)
	{
		$conn = $this->getConnection();
		return $conn->execute("SELECT count(*) as total_audience FROM user WHERE gender = '$gender' AND country_id = $country_id AND TIMESTAMPDIFF(YEAR, dob, NOW()) BETWEEN $min_age AND $max_age")->fetch('assoc');
	}

	public function totalAudienceAgainstGenderAndCity($min_age, $max_age, $gender, $city_id)
	{
		$conn = $this->getConnection();
		return $conn->execute("SELECT count(*) as total_audience FROM user WHERE gender = '$gender' AND city_id = $city_id AND TIMESTAMPDIFF(YEAR, dob, NOW()) BETWEEN $min_age AND $max_age")->fetch('assoc');
	}

	public function totalAudienceAgainstGenderAndState($min_age, $max_age, $gender, $state_id)
	{
		$conn = $this->getConnection();
		return $conn->execute("SELECT count(*) as total_audience FROM user WHERE gender = '$gender' AND city_id = $state_id AND TIMESTAMPDIFF(YEAR, dob, NOW()) BETWEEN $min_age AND $max_age")->fetch('assoc');
	}

	public function totalAudienceWithoutGenderAndCountry($min_age, $max_age, $country_id)
	{
		$conn = $this->getConnection();
		return $conn->execute("SELECT count(*) as total_audience FROM user WHERE country_id = $country_id AND TIMESTAMPDIFF(YEAR, dob, NOW()) BETWEEN $min_age AND $max_age")->fetch('assoc');
	}

	public function totalAudienceWithoutGenderAndCity($min_age, $max_age, $city_id)
	{
		$conn = $this->getConnection();
		return $conn->execute("SELECT count(*) as total_audience FROM user WHERE city_id = $city_id AND TIMESTAMPDIFF(YEAR, dob, NOW()) BETWEEN $min_age AND $max_age")->fetch('assoc');
	}

	public function totalAudienceWithoutGenderAndState($min_age, $max_age, $state_id)
	{
		$conn = $this->getConnection();
		return $conn->execute("SELECT count(*) as total_audience FROM user WHERE city_id = $state_id AND TIMESTAMPDIFF(YEAR, dob, NOW()) BETWEEN $min_age AND $max_age")->fetch('assoc');
	}

	public function totalAudienceAgainstCountryID($country_id): int
	{
		return $this->find()->where(['country_id' => $country_id])->count();
	}

	public function totalAudienceAgainstCityID($city_id): int
	{
		return $this->find()->where(['city_id' => $city_id])->count();
	}

	public function totalAudienceAgainstStateID($state_id): int
	{
		return $this->find()->where(['state_id' => $state_id])->count();
	}

	public function getAdminDetails()
	{
		return $this->find()->where(['role' => 'admin'])->all();
	}

	public function verifyCode($email, $code): int
	{
		return $this->find()->where(['email' => $email, 'token' => $code])->count();
	}

	public function verify($email, $user_password, $role)
	{
		if (!empty($email)) {
			$userData = $this->find()
				->where([
					'OR' => [
						['email' => $email],
						['username' => $email]
					],
					'active' => 1
				])
				->all()
				->toList();
			if (empty($userData)) {
				return false;
			}
		}
		$hasher = new DefaultPasswordHasher();
		if ($hasher->check($user_password, $userData[0]->password)) {
			return $userData;
		}
		return false;
	}

	public function verifyWithUsername($email, $user_password, $role)
	{
		if (!empty($email)) {
			$userData = $this->find()
				->where(['username' => $email, 'active' => 1])
				->all()
				->toList();
			if (empty($userData)) {
				return false;
			}
		}
		$hasher = new DefaultPasswordHasher();
		if ($hasher->check($user_password, $userData[0]->password)) {
			return $userData;
		}
		return false;
	}

	public function verifyPhoneNoAndPassword($phone_no, $user_password)
	{
		$userData = $this->find()->where(['phone_no' => $phone_no])->all()->toList();
		if (empty($userData)) {
			return false;
		}
		$hasher = new DefaultPasswordHasher();
		if ($hasher->check($user_password, $userData[0]->password)) {
			return $userData;
		}
		return false;
	}

	public function getUsers($starting_point)
	{
		return $this->find()
			->limit(ADMIN_RECORDS_PER_PAGE)
			->offset($starting_point * ADMIN_RECORDS_PER_PAGE)
			->order(['id' => 'DESC'])
			->all();
	}

	public function total_count_getUsers($role): int
	{
		return $this->find()->where(['role' => $role])->count();
	}

	public function getUserDetailsFromEmail($email)
	{
		return $this->find()->where(['email' => $email])->first();
	}

	public function beforeSave($event, $entity, $options)
	{
		if ($entity->isDirty('password')) {
			$hasher = new DefaultPasswordHasher();
			$entity->password = $hasher->hash($entity->password);
		}
	}
}
?>
