<?php

use Acms\Services\Facades\Common;

class ACMS_GET_Admin_Entry_TagJson extends ACMS_GET
{
    public $_scope = [
        'tag' => 'global',
    ];

    public function get()
    {
        if (!sessionWithContribution()) {
            die403();
        }

        $sql = $this->buildRelatedTagsQuery($this->tags);

        $rows = DB::query($sql->get(dsn()), 'all');
        $tagNames = array_column($rows, 'tag_name');

        Common::responseJson($tagNames);
    }

    /**
     * 選択中タグに紐づく他のタグを取得するSQLを組み立てる。
     *
     * 選択中タグが空の場合はブログ内の全タグを返す。
     * 選択中タグが指定されている場合は、公開側 Tag_Filter モジュール
     * (Acms\Modules\Get\Helpers\TagHelper::buildTagFilterQuery) と同様に
     * tag テーブルを選択タグの数だけ LEFT JOIN で積み重ね、選択タグを
     * 全て持つエントリーに絞り込んだ上で、そのエントリーに付与されている
     * 他のタグ（選択中のものを除く）を返す。
     *
     * ゴミ箱（entry_status = 'trash'）のエントリーに付与されたタグは
     * 候補に含めない。
     *
     * @param string[] $tags
     * @return \SQL_Select
     */
    protected function buildRelatedTagsQuery(array $tags): \SQL_Select
    {
        $sql = SQL::newSelect('tag', 'tag0');
        $sql->addSelect('tag_name', null, 'tag0');
        $sql->addWhereOpr('tag_blog_id', $this->bid, '=', 'AND', 'tag0');

        // タグが付与されたエントリーがゴミ箱でないことを担保する
        $sql->addLeftJoin('entry', 'entry_id', 'tag_entry_id', null, 'tag0');
        $sql->addWhereOpr('entry_status', 'trash', '<>', 'AND');

        foreach ($tags as $i => $tag) {
            $sql->addLeftJoin('tag', 'tag_entry_id', 'tag_entry_id', 'tag' . ($i + 1), 'tag' . $i);
            $sql->addWhereOpr('tag_name', $tag, '=', 'AND', 'tag' . ($i + 1));
        }
        foreach ($tags as $tag) {
            $sql->addWhereOpr('tag_name', $tag, '<>', 'AND', 'tag0');
        }

        $sql->addGroup('tag_name', 'tag0');
        $sql->addOrder('tag_name', 'asc', 'tag0');

        return $sql;
    }
}
