<?php 
class groupmembership implements crudable {

	private static array $fields=array(
		'userid'=>validator::INTEGER,
		'usergroupid'=>validator::INTEGER,
		'isgroupadmin'=>validator::BOOLEAN
	);

	public static array $helpTexts=array(
			'userid'=>'The ID of the user who is in the group',
			'usergroupid'=>'The id of the group the user belongs to',
			'isgroupadmin'=>'Whether the user can administer the group'
	);
	
	private static string $adminSelect='';
	private static string $normalSelect='';

	private static function getSelectClause(): string {
		if(session::isAdmin()){
			return self::$adminSelect;
		}
		return self::$normalSelect;
	}

    /**
     * @throws ServerException
     */
	public static function getFieldValidations(): array {
		throw new ServerException('getFieldValidations not implemented on groupmembership');
	}

    /**
     * @throws ServerException
     */
	public static function getFieldHelpTexts(): array {
		throw new ServerException('getFieldHelpTexts not implemented on groupmembership');
	}

	/**
	 * @return bool
	 * @throws BadRequestException
	 * @throws ServerException
	 */
	public static function canCreate(): bool {
		if(session::isAdmin()){ return true; }
		$sqlStatement='SELECT * FROM groupmembership WHERE userid=:userid AND isgroupadmin=1';
		$result=database::queryGetOne($sqlStatement, array(':userid'=>session::getUserId()));
		return !empty($result);
	}


	/**
	 * @param int $id
	 * @return array|null
	 * @throws BadRequestException
	 * @throws ServerException
	 */
	public static function getById(int $id): ?array {
		//TODO ACCESS CONTROLS ON THIS
		return database::queryGetOne('SELECT * FROM groupmembership WHERE id=:id', array(':id'=>$id));
	}

	/**
	 * @param string $name
	 * @return array|null
	 * @throws BadRequestException
	 */
	public static function getByName(string $name): ?array {
		throw new BadRequestException ('GetByName not implemented on groupmembership');
	}

	/**
	 * @param string $key
	 * @param string $value
	 * @param array $request
	 * @return array|null
	 * @throws BadRequestException
	 * @throws ServerException
	 */
	public static function getByProperty(string $key, string $value, array $request=[]): ?array {
		$className=get_called_class();
		//verify key in fields array
		$keys=array_keys(self::$fields);
		if(!in_array($key, $keys)){
			throw new BadRequestException('Property '.$key.' not recognised on '.$className);
		}
		$sqlStatement=self::getSelectClause().' AND '.$key.'=?:val';
		$sqlStatement.=database::getProjectClause('read');
		$sqlStatement.=database::getOrderClause($request, $className);
		$sqlStatement.=database::getLimitClause($request);
		$params=array(':val'=>$value);
		return database::queryGetAll($sqlStatement,$params);

	}

	/**
	 * @throws ServerException
	 */
	public static function getByProperties(array $keyValuePairs, array $request=[]):?array {
		throw new ServerException('getByProperties not implemented on groupmembership');
	}

    /**
     * @param array $request
     * @throws ServerException
     */
	public static function getAll(array $request=[]): ?array {
		throw new ServerException('getAll not implemented on groupmembership');
	}

	/**
	 * @param array $request
	 * @return array
	 * @throws BadRequestException
	 * @throws ForbiddenException
	 * @throws NotFoundException
	 * @throws ServerException
	 */
	public static function create(array $request=[]): array {
		if(!isset($request['userid'])|| !isset($request['usergroupid'])){
			throw new BadRequestException('Both userid and usergroupid are required');
		}
		static::checkCanManageMembership($request['usergroupid']);
		$userIsGroupAdmin=false;
		if(session::getUserId()==$request['userid'] || user::isAdmin($request['userid'])){
            //Don't reverse the above order - isAdmin will break the installer.
			//Administrators should be group admin by default
			//Person adding self to group should be admin
			$userIsGroupAdmin=true;
		} else if(isset($request['isgroupadmin']) && 1==$request['isgroupadmin']){
		    //Explicitly requested addition into group as admin, rather than add then promote.
		    $userIsGroupAdmin=true;
		}
		$sqlStatement='INSERT INTO groupmembership(userid,usergroupid,isgroupadmin) VALUES(:userid,:usergroupid,:isgroupadmin)';
		database::query($sqlStatement, array(':userid'=>$request['userid'], ':usergroupid'=>$request['usergroupid'], ':isgroupadmin'=>$userIsGroupAdmin));
		$createdId=database::getLastInsertId();
		return array('type'=>'groupmembership', 'created'=>static::getById($createdId));
	}

	/**
	 * @param int $id
	 * @param array $request
	 * @return array
	 * @throws BadRequestException
	 * @throws ForbiddenException
	 * @throws NotFoundException
	 * @throws ServerException
	 */
	public static function update(int $id, array $request=array()): array {
		$membership=self::getById($id);
		$group=usergroup::getById($membership['usergroupid']);
		static::checkCanManageMembership($group['id']);
		if(!isset($request['isgroupadmin']) || (0!=$request['isgroupadmin'] && 1!=$request['isgroupadmin'])){
			throw new BadRequestException('isgroupadmin should be supplied, and be 1 or 0');
		}
		database::query(
				'UPDATE groupmembership SET isgroupadmin=:isgroupadmin WHERE id=:id', 
				array(':isgroupadmin'=>$request['isgroupadmin'], ':id'=>$id)
		);
		return array('updated'=>static::getById($id));
	}

	/**
	 * @param int $id
	 * @return array
	 * @throws BadRequestException
	 * @throws ForbiddenException
	 * @throws NotFoundException
	 * @throws ServerException
	 */
	public static function delete(int $id): array {
		$membership=self::getById($id);
		$group=usergroup::getById($membership['usergroupid']);
		static::checkCanManageMembership($group['id']);
		$sqlStatement='DELETE FROM groupmembership where id=:id';
		database::query($sqlStatement, array(':id'=>$id));
		if(baseusergroup::ADMINISTRATORS==$group['name']){
			session::set('canCreateProjects', false);
		}
		return array('deleted'=>$id);
	}

	/**
	 * @param int $id
	 * @return bool
	 */
	public static function canUpdate(int $id): bool {
		return static::canManageMembership($id);
	}

	/**
	 * @param int $groupId
	 * @throws ForbiddenException
	 */
	private static function checkCanManageMembership(int $groupId): void {
		if(!static::canManageMembership($groupId)){
			throw new ForbiddenException('You do not have permission to do that');
		}
	}

	/**
	 * @param int $groupid
	 * @return bool
	 * @throws BadRequestException
	 * @throws ServerException
	 */
	private static function canManageMembership(int $groupid): bool {
		if(session::isAdmin() || session::canCreateUsergroups()){ return true; }
		$sqlStatement='SELECT * FROM groupmembership WHERE userid=:userid AND usergroupid=:groupid AND isgroupadmin=1';
		$result=database::queryGetOne($sqlStatement, array(':userid'=>session::getUserId(), ':groupid'=>$groupid));
		if(!empty($result)){ return true; }
		return false;
		//TODO If in "Usergroup creators" allow
	}
	
}