<?php

namespace Acms\Services\Unit;

use Acms\Services\Facades\Database as DB;
use SQL;

/**
 * 非推奨化されたテキストユニットのタグ選択（pre / none / markdown / wysiwyg）を、
 * 対応する専用ユニットへ一括変換する。column_add_type で追加された拡張ユニット
 * （例: "text_extend"）も対象に含む。拡張ユニットの指定子は既定では落とし、
 * 必要な場合のみ維持できる（詳細は LegacyTextTagMigration::resolveColumnType 参照）。
 *
 * @see https://developer.a-blogcms.jp/document/migration/302x/deprecated.html
 */
class LegacyTextTagMigrationRepository
{
    /**
     * 非推奨タグを使用しているテキストユニットを、対応する専用ユニットへ一括変換する。
     *
     * @param int $blogId
     * @param bool $preserveExtendSpecifier column_add_type の拡張ユニット指定子を移行後も維持するか
     * @param string[]|null $tags 変換対象に絞り込むタグ値。null の場合は対象タグ全て（既定挙動）
     * @return array{updated: int}
     */
    public function migrate(int $blogId, bool $preserveExtendSpecifier = false, ?array $tags = null): array
    {
        $targetTags = LegacyTextTagMigration::targetTags();
        $tags = $tags === null ? $targetTags : array_values(array_intersect($tags, $targetTags));

        $updated = 0;
        foreach (['column', 'column_rev'] as $table) {
            foreach ($tags as $tag) {
                $updated += $this->updateTag($table, $blogId, $tag, $preserveExtendSpecifier);
            }
        }

        return ['updated' => $updated];
    }

    /**
     * 指定タグを使用している column_type（"text" および "text_xxx" 拡張ユニット）ごとに、
     * 対応する移行先タイプへの UPDATE を実行する。
     *
     * @param 'column'|'column_rev' $table
     * @return int 更新した行数
     */
    private function updateTag(string $table, int $blogId, string $tag, bool $preserveExtendSpecifier): int
    {
        $updated = 0;
        foreach ($this->collectTextColumnTypes($table, $blogId, $tag) as $originalColumnType) {
            $newColumnType = LegacyTextTagMigration::resolveColumnType($tag, $originalColumnType, $preserveExtendSpecifier);
            if ($newColumnType === null) {
                continue;
            }

            $sql = SQL::newUpdate($table);
            $sql->addUpdate('column_type', $newColumnType);
            $sql->addUpdate('column_field_2', '');
            $sql->addUpdate('column_field_3', '');
            $sql->addWhereOpr('column_type', $originalColumnType);
            $sql->addWhereOpr('column_field_2', $tag);
            $sql->addWhereOpr('column_blog_id', $blogId);
            DB::query($sql->get(dsn()), 'exec');
            $updated += DB::affected_rows();
        }

        return $updated;
    }

    /**
     * 指定タグを使用している行の column_type（重複なし）のうち、
     * テキストユニット（"text" または "text_xxx" 拡張ユニット）に該当するものだけを取得する。
     *
     * @param 'column'|'column_rev' $table
     * @return string[]
     */
    private function collectTextColumnTypes(string $table, int $blogId, string $tag): array
    {
        $sql = SQL::newSelect($table);
        $sql->addSelect('column_type', null, null, 'DISTINCT');
        $sql->addWhereOpr('column_field_2', $tag);
        $sql->addWhereOpr('column_blog_id', $blogId);
        $rows = DB::query($sql->get(dsn()), 'all');

        $columnTypes = [];
        foreach ($rows as $row) {
            if (detectUnitTypeSpecifier($row['column_type']) === 'text') {
                $columnTypes[] = $row['column_type'];
            }
        }

        return $columnTypes;
    }
}
