<?php

use Acms\Services\Blog\BlogRepository;
use Acms\Services\Facades\Application;
use Acms\Services\Facades\Field as FieldFacade;

class ACMS_POST_Blog_Insert extends ACMS_POST
{
    /**
     * @var mixed
     */
    protected $workflowData = false;

    public function post()
    {
        $blogRepository = Application::make('blog.repository');
        assert($blogRepository instanceof BlogRepository);

        $Blog = $this->extract('blog');
        $Blog->setMethod('status', 'required');
        $Blog->setMethod('status', 'in', ['open', 'close', 'secret']);
        $Blog->setMethod('status', 'status', Blog::isValidStatus($Blog->get('status')));
        $Blog->setMethod('status', 'root', true);
        $Blog->setMethod('name', 'required');
        $Blog->setMethod('name', 'maxlength', '255');
        $Blog->setMethod('domain', 'required');
        $Blog->setMethod('domain', 'maxlength', '128');
        $Blog->setMethod('domain', 'domain', Blog::isDomain($Blog->get('domain'), $this->Get->get('aid')));
        $Blog->setMethod('code', 'maxlength', '255');
        $Blog->setMethod('code', 'exists', Blog::isCodeExists($Blog->get('domain'), $Blog->get('code')));
        $Blog->setMethod('code', 'reserved', !isReserved($Blog->get('code')));
        if ($Blog->get('code') !== '') {
            $Blog->setMethod('code', 'string', isValidCode($Blog->get('code'), allowSlash: true));
        }
        $Blog->setMethod('config_set_id', 'value', $this->checkConfigSetScope($Blog->get('config_set_id')));
        $Blog->setMethod('config_set_scope', 'in', ['local', 'global']);
        $Blog->setMethod('theme_set_id', 'value', $this->checkConfigSetScope($Blog->get('theme_set_id')));
        $Blog->setMethod('theme_set_scope', 'in', ['local', 'global']);
        $Blog->setMethod('editor_set_id', 'value', $this->checkConfigSetScope($Blog->get('editor_set_id')));
        $Blog->setMethod('editor_set_scope', 'in', ['local', 'global']);
        $Blog->setMethod('indexing', 'required');
        $Blog->setMethod('indexing', 'in', ['on', 'off']);
        $Blog->setMethod('blog', 'operable', Blog::canCreate(BID));
        $Blog->validate(new ACMS_Validator());
        $Field = $this->extract('field', new ACMS_Validator());
        $Config = $this->extract('config', new ACMS_Validator());

        if (sessionWithEnterpriseAdministration()) {
            $this->workflowData = $this->extractWorkflow();
        }

        if ($this->Post->isValidAll()) {
            //-------
            // align
            $lastChild = $blogRepository->findLastChildInParent(BID);
            if ($lastChild !== null) {
                $l      = $lastChild['right'] + 1;
                $r      = $l + 1;
                $sort   = $lastChild['sort'] + 1;
            } else {
                $l      = ACMS_RAM::blogRight(BID);
                $r      = $l + 1;
                $sort   = 1;
            }

            //--------
            // adjust
            $blogRepository->shiftLeftRightAfter($l);

            Cache::flush('temp');

            //------
            // insert
            $bid = $blogRepository->nextBlogId();

            $configSetId = $this->normalizeSetId($Blog->get('config_set_id'));
            $themeSetId = $this->normalizeSetId($Blog->get('theme_set_id'));
            $editorSetId = $this->normalizeSetId($Blog->get('editor_set_id'));

            if ($configSetId === null) {
                $Blog->set('config_set_scope', 'local');
            }
            if ($themeSetId === null) {
                $Blog->set('theme_set_scope', 'local');
            }
            if ($editorSetId === null) {
                $Blog->set('editor_set_scope', 'local');
            }

            $blogRepository->insert([
                'blog_id' => $bid,
                'blog_left' => $l,
                'blog_right' => $r,
                'blog_sort' => $sort,
                'blog_parent' => BID,
                'blog_generated_datetime' => date('Y-m-d H:i:s', REQUEST_TIME),
                'blog_status' => $Blog->get('status'),
                'blog_name' => $Blog->get('name'),
                'blog_code' => trim(strval($Blog->get('code')), '/'),
                'blog_domain' => $Blog->get('domain'),
                'blog_indexing' => $Blog->get('indexing'),
                'blog_config_set_id' => $configSetId,
                'blog_config_set_scope' => $Blog->get('config_set_scope', 'local'),
                'blog_theme_set_id' => $themeSetId,
                'blog_theme_set_scope' => $Blog->get('theme_set_scope', 'local'),
                'blog_editor_set_id' => $editorSetId,
                'blog_editor_set_scope' => $Blog->get('editor_set_scope', 'local'),
            ]);

            //-------
            // field
            FieldFacade::save('bid', $bid, $Field);

            //--------
            // config
            Config::saveConfig($Config, $bid);

            //----------
            // geometry
            $this->saveGeometry('bid', $bid, $this->extract('geometry'));

            //----------
            // workflow
            if (sessionWithEnterpriseAdministration() && $this->workflowData) {
                $this->saveWorkflow($this->workflowData, $bid);
            }

            //-------------
            // for display
            $Blog->set('id', $bid);

            Fulltext::saveFulltext('bid', $bid, Fulltext::loadBlogFulltext($bid));

            AcmsLogger::info('「' . ACMS_RAM::blogName($bid) . '」ブログを作成しました');

            // 作成したブログは別ドメイン / サブドメインになりうる。リンクにしておけば
            // ユーザーがクリックしたときだけ能動的にそのドメインへ遷移できる。
            $this->addMessage('ブログを作成しました。', [
                'url' => (string) acmsLink([
                    'bid' => $bid,
                    'admin' => 'blog_edit',
                ]),
                'label' => ACMS_RAM::blogName($bid) . 'にアクセスする。',
            ]);

            // PRG: 現ドメインのブログ新規作成フォームへリダイレクトする（リロードによる二重登録を防ぐ）
            $this->redirect(acmsLink($this->buildPostInsertRedirect(idval((string) BID))));
        } else {
            AcmsLogger::info('ブログの作成に失敗しました', [
                'validator' => $Blog->_aryV,
            ]);
        }

        return $this->Post;
    }

    /**
     * config_set / theme_set / editor_set の ID をフォーム値から正規化する
     * 空文字や 0 を null に揃える
     */
    private function normalizeSetId(string $rawId): ?int
    {
        if ($rawId === '' || $rawId === '0') {
            return null;
        }
        return (int) $rawId;
    }

    /**
     * ブログ作成後（PRG）のリダイレクト先を組み立てるための acmsLink() 引数を返す。
     *
     * 作成したブログは別ドメイン / サブドメインになりうる。別ドメインへ 302 すると
     * セッション Cookie が届かず未ログインになるため、ドメインに関わらず必ず現在の
     * 管理ドメイン（$currentBlogId = BID）のブログ新規作成フォームへ留める。
     *
     * @param int $currentBlogId 現在の管理ドメインのブログ ID（BID）
     * @return array{bid: int, admin: string, query: array<string, mixed>}
     */
    private function buildPostInsertRedirect(int $currentBlogId): array
    {
        return [
            'bid' => $currentBlogId,
            'admin' => 'blog_edit',
            'query' => [],
        ];
    }
}
