<?php

namespace AuthStack\SAMLServiceProvider\Model;

use Illuminate\Support\Collection;
use LightSaml\Model\{
    Assertion\Assertion,
    Assertion\Attribute,
    Assertion\AttributeStatement,
    Assertion\NameID,
    Protocol\Response,
    Context\DeserializationContext,
    Assertion\EncryptedAssertionReader
};

class AuthNResponse
{
    /**
     * @var ServiceProvider
     */
    protected $sp;

    /**
     * @var Response
     */
    protected $response;

    /**
     * @var Collection
     */
    protected $assertions;

    /**
     * @var Collection
     */
    protected $attributes;

    /**
     * @var Collection
     */
    protected $name_ids;

    public function __construct(Response $response, ServiceProvider $sp)
    {
        $this->response = $response;
        $this->sp = $sp;

        $this->extractAssertions();
        $this->extractAttributes();
        $this->extractNameIDs();
    }

    public function getOriginalResponse(): Response
    {
        return $this->response;
    }

    /**
     * @return string
     */
    public function getNameIdValue()
    {
        /** @var  $name_id NameID */
        $name_id = $this->name_ids->first();

        return $name_id->getValue();
    }

    /**
     * @return null|string
     */
    public function getNameIdFormat()
    {
        /** @var  $name_id NameID */
        $name_id = $this->name_ids->first();

        return $name_id->getFormat();
    }

    /**
     * @return Collection
     */
    public function getNameIDs(): Collection
    {
        return $this->name_ids;
    }

    /**
     * @return array
     */
    public function getAttributes(): array
    {
        return $this->getAttributeCollection()->toArray();
    }

    /**
     * @return Collection
     */
    public function getAssertionCollection(): Collection
    {
        return $this->assertions;
    }

    /**
     * @return Collection
     */
    public function getAttributeCollection(): Collection
    {
        return $this->attributes;
    }

    /**
     *
     */
    protected function extractAssertions(): void
    {
        if($this->sp->wantsEncryptedAssertions())
        {
            $context = new DeserializationContext();

            $decryptionKey = $this->sp->getDecrypter();

            $assertions = collect($this->response->getAllEncryptedAssertions())
                ->map(function(EncryptedAssertionReader $encryptedAssertion) use (&$decryptionKey, &$context)
                {
                    return $encryptedAssertion->decryptAssertion($decryptionKey, $context);
                }
            );
        }
        else
        {
            $assertions = collect($this->response->getAllAssertions());
        }

        $this->assertions = $assertions;
    }

    /**
     *
     */
    protected function extractAttributes(): void
    {
        // The resulting collection will contain \LightSaml\Model\Assertion\Attribute
        $this->assertions->map(function(Assertion $assertion)
        {
            $statements = $assertion->getAllAttributeStatements();

            return collect($statements)->map(function(AttributeStatement $statement)
            {
                return collect($statement->getAllAttributes())->map(function(Attribute $item)
                {
                    $value = count($item->getAllAttributeValues()) > 1 ? $item->getAllAttributeValues() : $item->getFirstAttributeValue();

                    $this->attributes[] = [
                        'name' => $item->getName(),
                        'value' => $value
                    ];
                })->toArray();

            })->toArray();
        });

        $this->attributes = collect($this->attributes);
    }

    protected function extractNameIDs(): void
    {
        $this->name_ids = $this->assertions->map(function(Assertion $assertion)
        {
            return $assertion->getSubject()->getNameID();
        });
    }
}