<?php

namespace AuthStack\SP\Helpers;

use LightSaml\Model\Metadata\EntityDescriptor;
use LightSaml\Model\Metadata\IdpSsoDescriptor;
use LightSaml\Model\Metadata\SingleLogoutService;
use LightSaml\Model\Metadata\SingleSignOnService;
use LightSaml\Model\Metadata\KeyDescriptor;

class IDPParser
{
    /**
     * @var EntityDescriptor
     */
    protected $entityDescriptor;

    /**
     * @var string|null
     */
    protected $entityID = null;

    /**
     * @var SingleSignOnService
     */
    protected $ssoService = null;

    /**
     * @var SingleLogoutService
     */
    protected $sloService = null;

    /**
     * @var string|null
     */
    protected $x509 = null;

    /**
     * @var bool
     */
    protected $wantsAuthnRequestsSigned = false;

    public function __construct($metadata)
    {
        $this->parseIDPMetadata($metadata);
    }

    /**
     * @return string
     * @throws \Exception
     */
    public function getPHPTemplate()
    {
        if(empty($this->entityID))
        {
            throw new \Exception('Could not read IDP entityID.');
        }

        return sprintf("sha1('%s') => [
                            'entityId' => '%s',
                            %s
                            %s
                            %s
                            %s
                        ]",
            $this->entityID,
            $this->entityID,
            $this->getSSOTemplateString(),
            $this->getSLOTemplateString(),
            $this->getX509TemplateString(),
            $this->getWantsSignedRequestsString());
    }

    /**
     * @param $metadata
     * 
     * @return null
     */
    protected function parseIDPMetadata($metadata)
    {
        $this->entityDescriptor = EntityDescriptor::loadXml($metadata);

        if(empty($this->entityDescriptor->getEntityID()))
        {
            throw new \Exception('Unable to read entityID from the given metadata.');
        }

        $this->entityID = $this->entityDescriptor->getEntityID();

        $items = $this->entityDescriptor->getAllItems();

        if(empty($items))
        {
            throw new \Exception('Unable to read SAML2.0 relevant data from the given metadata.');
        }

        foreach($items as $item)
        {
            if($item instanceof IdpSsoDescriptor)
            {
                $this->wantsAuthnRequestsSigned = $item->getWantAuthnRequestsSigned() ? true : false;

                $this->ssoService = $item->getFirstSingleSignOnService();
                $this->sloService = $item->getFirstSingleLogoutService();

                $keyDescriptors = $item->getAllKeyDescriptors();

                if(!empty($keyDescriptors))
                {
                    foreach($keyDescriptors as $keyDescriptor)
                    {
                        if($keyDescriptor->getUse() == KeyDescriptor::USE_SIGNING)
                        {
                            $this->x509 = $keyDescriptor->getCertificate();
                        }
                    }
                }
            }
        }
    }

    /**
     * @return string
     * @throws \Exception
     */
    protected function getSSOTemplateString()
    {
        if(empty($this->ssoService->getBinding()) || empty($this->ssoService->getLocation()))
        {
            throw new \Exception('Could not read SSO service binding or location.');
        }

        return "'SSO' => [
                    'url' => '{$this->ssoService->getLocation()}',
                    'binding' => '{$this->ssoService->getBinding()}'
                ],";
    }

    /**
     * @return string
     */
    protected function getSLOTemplateString()
    {
        if(empty($this->sloService->getBinding()) || empty($this->sloService->getLocation()))
        {
            return '';
        }

        return "'SLO' => [
                    'url' => '{$this->sloService->getLocation()}',
                    'binding' => '{$this->sloService->getBinding()}'
                ],";
    }

    protected function getX509TemplateString()
    {
        if(empty($this->x509))
        {
            return '';
        }

        return "'x509' => '{$this->x509}',";
    }

    /**
     * @return string
     */
    protected function getWantsSignedRequestsString()
    {
        return $this->wantsAuthnRequestsSigned ? "'wantsSignedRequests' => true," : "'wantsSignedRequests' => false,";
    }
}
