<?php

class shibboleth {

    const USER_LINKED = "user_linked";
    const USER_CREATED = "user_created";
    const USER_CONFLICT = "user_conflict";

    public static function getIdentityProviderEntityId(): ?string {
        if(isset($_SERVER['Shib-Identity-Provider'])){
            return $_SERVER['Shib-Identity-Provider'];
        }
        return null;
    }

    public static function getIdentityProviders(): mixed {
        $path=rtrim($_SERVER['DOCUMENT_ROOT'],'/').'/conf/identityProviders.json';
        if(file_exists($path) && $content=@file_get_contents($path)){
            $content=json_decode($content,true);
            if($content && isset($content['identityProviders'])){ return $content['identityProviders']; }
        }
        return [];
    }

    public static function isAuthenticated(): bool {
		//Is there a SAML entityID in the server variables?
		$entityId=static::getIdentityProviderEntityId();
		return !empty($entityId);
    }

	/**
	 * @throws ServerException
	 */
	public static function getSamlUser(): ?array {
		return static::getSamlUserAttributes();
	}

    /**
     * @throws ServerException
     */
    private static function getSamlUserAttributes(): ?array {
        if(!static::isAuthenticated()){ return null; }
        $attributes=['mail','eppn','givenName','fullName','familyName','displayName','orcid'];
        $user=[];
        foreach($attributes as $attr){
            $value=static::getSingleValueFromAttribute($attr);
            if(!empty($value)){ $user[$attr]=$value; }
        }
        $aliases=[
            'email'=>'mail',
            'eduPersonPrincipalName'=>'eppn',
            'firstName'=>'givenName',
            'lastName'=>'familyName',
            'surname'=>'familyName'
        ];
        foreach($aliases as $alias=>$attribute){
            if(!isset($user[$attribute])){
                $value=static::getSingleValueFromAttribute($alias);
                if(!empty($value)){ $user[$attribute]=$value; }
            }
        }
        return $user;
    }

    /**
     * @throws ServerException
     */
    private static function getSingleValueFromAttribute(string $attribute): ?string {
        if(!isset($_SERVER[$attribute])){ return null; }
        $parts=explode(';', $_SERVER[$attribute]);
        if(1===count($parts)){ return $parts[0]; }
        for($i=1;$i<count($parts);$i++){
            if($parts[0]!==$parts[$i]){
                throw new ServerException("Multiple and different values for single-value SAML attribute $attribute: [".implode(';',$parts)."]");
            }
        }
        return $parts[0];
    }

    /**
	 * @return array
     * @throws \Random\RandomException
     * @throws NotFoundException
     * @throws ForbiddenException
     * @throws BadRequestException
     * @throws ServerException
     */
    public static function createIceBearUser(): array {
		session::becomeAdmin();
        $samlUser=static::getSamlUserAttributes();
		if(!isset($samlUser['eppn'])) {
			throw new ServerException('No eppn property on Shibboleth user');
		}
		if(!isset($samlUser['mail'])) {
			throw new ServerException('No mail property on Shibboleth user');
		}
        $nameMatch=user::getByProperty('edupersonprincipalname',$samlUser['eppn']);
		if($nameMatch) {
			throw new BadRequestException('An account with this eduPersonPrincipalName already exists');
		}

		$iceBearUser=[
			'isactive'=>'1',
			'email'=>$samlUser['mail'],
			'password'=>random_bytes(32) //never using this, but database complains without it,
		];

		$iceBearUser['edupersonprincipalname']=$samlUser['eppn'];
		$iceBearUser['name']=$samlUser['eppn'];

		//Set the user's "full name"
		if(isset($samlUser['displayName'])){
			$iceBearUser['fullname']=$samlUser['displayName'];
		} else if(isset($samlUser['commonName'])){
			$iceBearUser['fullname']=$samlUser['commonName'];
		} else if(isset($samlUser['fullName'])){
			$iceBearUser['fullname']=$samlUser['fullName'];
		} else if(isset($samlUser['givenName']) && isset($samlUser['familyName'])){
			$iceBearUser['fullname']=$samlUser['familyName'].', '.$samlUser['givenName'];
		} else {
			throw new ServerException('Cannot create IceBear user - no usable name in SAML attributes');
		}

		$user=user::create($iceBearUser);
        session::revertAdmin();
        return $user;
    }

	/**
	 * @throws BadRequestException
	 * @throws ForbiddenException
	 * @throws AuthorizationRequiredException
	 * @throws ServerException
	 * @throws NotFoundException
	 */
	public static function setUserToIceBearSession(): void {
		$samlUser=static::getSamlUserAttributes();
		if(!isset($samlUser['eppn'])) {
			throw new ServerException('No eppn property on Shibboleth user');
		}
		session::becomeAdmin();
		$iceBearUser=user::getByProperty('edupersonprincipalname',$samlUser['eppn']);
		session::revertAdmin();
		if(!$iceBearUser){
			throw new NotFoundException('No IceBear user with edupersonprincipalname '.$samlUser['eppn']);
		}
		if(1!=count($iceBearUser['rows'])){
			throw new ServerException('Multiple IceBear users with edupersonprincipalname '.$samlUser['eppn']);
		}
		$iceBearUser=$iceBearUser['rows'][0];
		session::setUserToSession($iceBearUser['name']);
	}

}