<?php

namespace AuthStack\SAMLServiceProvider\Model;

use LightSaml\Credential\KeyHelper;
use LightSaml\Credential\X509Certificate;
use LightSaml\Model\XmlDSig\SignatureWriter;
use RobRichards\XMLSecLibs\XMLSecurityKey;

class IdentityProvider
{
    protected $entity_id;

    public function __construct(string $entity_id)
    {
        $this->entity_id = $entity_id;
    }

    /**
     * @return \Illuminate\Config\Repository|mixed
     */
    public function getBaseUrl()
    {
        return $this->fromConfig('baseUrl');
    }

    /**
     * @return string
     */
    public function getEntityID(): string
    {
        return $this->entity_id;
    }

    /**
     * @return string
     */
    public function getSSOUrl(): string
    {
        return sprintf("%s%s", $this->getBaseUrl(), $this->fromConfig('SSO.url'));
    }

    /**
     * @return string
     */
    public function getSSOBinding(): string
    {
        return $this->fromConfig('SSO.binding');
    }

    /**
     * @return string
     */
    public function getLogoutURL(): string
    {
        return sprintf("%s%s", $this->getBaseUrl(), $this->fromConfig('SLO.url'));
    }

    /**
     * @return string
     */
    public function getLogoutBinding(): string
    {
        return $this->fromConfig('SLO.binding');
    }

    /**
     * @return \Illuminate\Config\Repository|mixed
     */
    public function getX509()
    {
        return $this->fromConfig('x509');
    }

    /**
     * @return XMLSecurityKey
     */
    public function getPublicKey(): XMLSecurityKey
    {
        return KeyHelper::createPublicKey(
            (new X509Certificate())->setData($this->getX509())
        );
    }

    /**
     * @return bool
     */
    public function wantsSignedReguests(): bool
    {
        return $this->fromConfig('wantsSignedRequests');
    }

    /**
     * @param string $path
     * @return \Illuminate\Config\Repository|mixed
     */
    protected function fromConfig(string $path)
    {
        $path = sprintf("saml.idp.%s.%s", sha1($this->entity_id), $path);

        return config($path);
    }

    /**
     * @return XMLSecurityKey
     */
    public function getSigningPublicKey(): XMLSecurityKey
    {
        return KeyHelper::createPublicKey(
            (new X509Certificate())->setData($this->getSigningKeyX509Cert())
        );
    }

    /**
     * @return SignatureWriter
     */
    public function getSignatureWriter(): SignatureWriter
    {
        $x509 = new X509Certificate();

        $x509->setData($this->getSigningKeyX509Cert());

        $priv = KeyHelper::createPrivateKey(
            $this->getSigningPrivateKey(),
            $this->getSigningPrivateKeyPassphrase(),
            false,
            $this->getSigningDigestAlgorithm()
        );

        return new SignatureWriter($x509, $priv);
    }

    /**
     * @return string
     */
    public function getSigningKeyX509Cert(): string
    {
        return config(sprintf('saml.idp.%s.keys.signing.x509', sha1($this->getEntityID())));
    }

    /**
     * @return string
     */
    public function getSigningPrivateKey(): string
    {
        return config(sprintf('saml.idp.%s.keys.signing.private', sha1($this->getEntityID())));
    }

    /**
     * @return null|string
     */
    public function getSigningPrivateKeyPassphrase(): ?string
    {
        return config(sprintf('saml.idp.%s.keys.signing.passphrase', sha1($this->getEntityID())));
    }

    /**
     * @return string
     */
    public function getSigningDigestAlgorithm(): string
    {
        return config(sprintf('saml.idp.%s.keys.signing.algorithm', sha1($this->getEntityID())));
    }

    /**
     * @return \DateTime
     */
    public function getUpperDT(): \DateTime
    {
        return new \DateTime($this->getValidationUpperTimeBoundary(), new \DateTimeZone('UTC'));
    }

    /**
     * @return \DateTime
     */
    public function getLowerDT(): \DateTime
    {
        return new \DateTime($this->getValidationLowerTimeBoundary(), new \DateTimeZone('UTC'));
    }

    /**
     * @return string
     */
    public function getValidationUpperTimeBoundary(): string
    {
        return config(sprintf('saml.idp.%s.upper', sha1($this->getEntityID())));
    }

    /**
     * @return string
     */
    public function getValidationLowerTimeBoundary(): string
    {
        return config(sprintf('saml.idp.%s.lower', sha1($this->getEntityID())));
    }
}