<?php

use Acms\Services\Blog\BlogRepository;
use Acms\Services\Facades\Application;

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

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

        $Blog = $this->extract('blog');
        $deleteField = new Field();
        $Field  = $this->extract('field', new ACMS_Validator(), $deleteField);
        $Config = $this->extract('config', new ACMS_Validator());
        $this->validate($Blog, $Field, $Config);

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

        if ($this->Post->isValidAll()) {
            $status = $Blog->get('status');
            if ($status !== 'open') {
                $aryStatus = ['open'];
                if ($status === 'close') {
                    $aryStatus[] = 'secret';
                }
                $blogRepository->updateDescendantsStatus(BID, $status, $aryStatus);
            }

            $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->update(BID, [
                'blog_status' => $status,
                'blog_name' => $Blog->get('name'),
                'blog_code' => trim(strval($Blog->get('code')), '/'),
                'blog_domain' => $Blog->get('domain'),
                'blog_indexing' => strval($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'),
            ]);

            Cache::flush('temp');

            //-------
            // field
            Common::saveField('bid', BID, $Field, $deleteField);

            //--------
            // config
            Config::saveConfig($Config, BID);
            Config::set('blog_theme_color', $Config->get('blog_theme_color'));
            Config::set('blog_theme_logo@squarePath', $Config->get('blog_theme_logo@squarePath'));


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

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

            //------------
            // update RAM
            if ($row = $blogRepository->findBlogById(BID)) {
                ACMS_RAM::blog(BID, $row);
            }

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

            $this->Post->set('edit', 'update');
            Common::saveFulltext('bid', BID, Common::loadBlogFulltext(BID));

            AcmsLogger::info('「' . ACMS_RAM::blogName(BID) . '」ブログを更新しました');
        } else {
            AcmsLogger::info('ブログの更新に失敗しました', [
                'blogValidator' => $Blog->_aryV,
                'fieldValidator' => $Field->_aryV,
                'configValidator' => $Config->_aryV,
            ]);
        }

        return $this->Post;
    }

    /**
     *  バリデート
     *
     * @param \Field_Validation $Blog
     * @param \Field_Validation $Field
     * @param \Field_Validation $Config
     */
    protected function validate(
        \Field_Validation $Blog,
        \Field_Validation $Field,
        \Field_Validation $Config
    ) {
        $Blog->setMethod('status', 'required');
        $Blog->setMethod('status', 'in', ['open', 'close', 'secret']);
        $Blog->setMethod('status', 'status', Blog::isValidStatus($Blog->get('status'), true));
        $Blog->setMethod('status', 'root', !(RBID === BID && $Blog->get('status') === 'close'));
        $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'), false, true));
        $Blog->setMethod('code', 'maxlength', '255');
        $Blog->setMethod('code', 'exists', Blog::isCodeExists($Blog->get('domain'), $Blog->get('code'), BID));
        $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', $this->isOperable());
        $Blog->validate(new ACMS_Validator());
        $Field->validate(new ACMS_Validator());
        $Config->validate(new ACMS_Validator());
    }

    /**
     * ブログの更新が可能か
     *
     * セッション管理者として認可されているか、もしくはショートカット経由で許可されているかを判定する。
     * ショートカット権限の検証はモジュール固有の関心事のためここに残す。
     */
    protected function isOperable(): bool
    {
        if (Blog::canUpdate(BID)) {
            return true;
        }
        if (Auth::checkShortcut(['bid' => BID])) {
            return true;
        }
        return false;
    }

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