<?php

namespace JsonApi\Routes\Courseware;

use JsonApi\Errors\AuthorizationFailedException;
use JsonApi\JsonApiController;
use JsonApi\Routes\ValidationTrait;
use JsonApi\Schemas\Courseware\StructuralElement as StructuralElementSchema;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Studip\Activity\Activity;

/**
 * Create a block in a container.
 */
class StructuralElementsCreate extends JsonApiController
{
    use ValidationTrait;

    /**
     * @SuppressWarnings(PHPMD.UnusedFormalParameter)
     */
    public function __invoke(Request $request, Response $response, $args)
    {
        $json = $this->validate($request);
        $parent = $this->getParentFromJson($json);
        if (!Authority::canCreateStructuralElement($user = $this->getUser($request), $parent)) {
            throw new AuthorizationFailedException();
        }
        $struct = $this->createStructuralElement($user, $json, $parent);

        return $this->getCreatedResponse($struct);
    }

    /**
     * @SuppressWarnings(PHPMD.UnusedFormalParameters)
     */
    protected function validateResourceDocument($json, $data)
    {
        if (!self::arrayHas($json, 'data')) {
            return 'Missing `data` member at document“s top level.';
        }
        if (StructuralElementSchema::TYPE !== self::arrayGet($json, 'data.type')) {
            return 'Wrong `type` member of document“s `data`.';
        }
        if (self::arrayHas($json, 'data.id')) {
            return 'New document must not have an `id`.';
        }

        if (!self::arrayHas($json, 'data.attributes.title')) {
            return 'Missing `title` attribute.';
        }

        if (!self::arrayHas($json, 'data.relationships.parent')) {
            return 'Missing `parent` relationship.';
        }
        if (!$this->getParentFromJson($json)) {
            return 'Invalid `parent` relationship.';
        }
    }

    private function getParentFromJson($json)
    {
        if (!$this->validateResourceObject($json, 'data.relationships.parent', StructuralElementSchema::TYPE)) {
            return null;
        }
        $parentId = self::arrayGet($json, 'data.relationships.parent.data.id');

        return \Courseware\StructuralElement::find($parentId);
    }

    private function createStructuralElement(\User $user, array $json, \Courseware\StructuralElement $parent)
    {
        $struct = \Courseware\StructuralElement::build([
            'parent_id' => $parent->id,
            'range_id' => $parent->range_id,
            'range_type' => $parent->range_type,
            'owner_id' => $user->id,
            'editor_id' => $user->id,
            'edit_blocker_id' => '',
            'title' => self::arrayGet($json, 'data.attributes.title', ''),
            'purpose' => self::arrayGet($json, 'data.attributes.purpose', $parent->purpose),
            'payload' => self::arrayGet($json, 'data.attributes.payload', ''),
            'read_approval' => self::arrayGet($json, 'data.attributes.read-approval', []),
            'write_approval' => self::arrayGet($json, 'data.attributes.write-approval', []),
            'position' => $parent->countChildren()
        ]);

        $struct->store();
        $template = \Courseware\Template::find(self::arrayGet($json, 'data.templateId'));

        if ($template) {
            $structure = json_decode($template->structure, true);

            foreach($structure['containers'] as $container) {

                $new_container = \Courseware\Container::build([
                    'structural_element_id' => $struct->id,
                    'owner_id' => $user->id,
                    'editor_id' => $user->id,
                    'edit_blocker_id' => '',
                    'position' => $struct->countContainers(),
                    'container_type' => $container['attributes']['container-type'],
                    'payload' => json_encode($container['attributes']['payload']),
                ]);

                $new_container->store();
                $blockMap = [];
                foreach($container['blocks'] as $block) {
                    $new_block = \Courseware\Block::build([
                        'container_id'    => $new_container->id,
                        'owner_id'        => $user->id,
                        'editor_id'       => $user->id,
                        'position'        => $new_container->countBlocks(),
                        'block_type'      => $block['attributes']['block-type'],
                        'payload'         => json_encode($block['attributes']['payload']),
                        'visible'         => 1,
                    ]);

                    $new_block->store();
                    $blockMap[$block['id']] = $new_block->id;
                }
                $new_container['payload'] = $new_container->type->copyPayload($blockMap);
                $new_container->store();
            }
        }

        return $struct;
    }
}