<?php

namespace Acms\Traits\Utilities;

use Acms\Services\Facades\Template as TemplateHelper;
use Acms\Services\Facades\Application;
use Field;
use Field_Validation;

/**
 * テンプレート出力固有の処理を担うトレイト。
 *
 * Field の構造化（フィールドキーの分類・グループ展開・型自動変換・バリデーション結果の上乗せ）
 * は Field 本体の toStructured() に委譲する。本トレイトの責務は次の 3 つに限る:
 *
 *  1. メディア・リッチエディタ・ブロックエディタの注入（Template Service への依存）
 *  2. path フィールドの URL 解決 / html フィールドの絶対化（Url Service への依存）
 *  3. テンプレート側で元 Field を取り回すための takeover キー（acmsSerialize で保存）
 *
 * これらは Field 本体に持ち込むと階層違反になるため、トレイト側に残す。
 */
trait FieldTrait
{
    /**
     * フィールドを連想配列として組み立て
     *
     * @param Field|Field_Validation $field
     * @param string|null $scp 子フィールドとして再帰したときの名前（takeover キーの prefix に使う）
     * @return array|null フィールドが空の場合は null
     */
    protected function buildFieldTrait($field, ?string $scp = null): ?array
    {
        // テンプレート出力固有の前処理（メディア・リッチエディタ・ブロックエディタの注入）
        TemplateHelper::injectMediaField($field);
        TemplateHelper::injectRichEditorField($field);
        TemplateHelper::injectBlockEditorField($field, ['resizeImage' => true, 'enableFilterHook' => true]);

        // 構造化は Field 本体に委譲。子フィールド再帰は takeover との組合せが必要なため
        // ここでは行わず、後段で手動で foreach する。
        $builtData = $field->toStructured(
            autoConvert: true,
            withValidation: !isApiBuild(),
            recursive: false,
        );

        // テンプレート出力固有の後処理: path フィールドの URL 解決、html フィールドの絶対化
        $builtData = $this->resolveTemplateUrlsTrait($builtData, $field);

        // takeover キー: テンプレート側で元 Field を取り回すための serialize 保存
        if (!isApiBuild() && !is_null($scp)) {
            $builtData[($scp ? "{$scp}:" : '') . 'takeover'] = acmsSerialize($field);
        }

        // 子フィールド再帰（再帰時 $scp=child により子側にも takeover キーが付く既存挙動を維持）
        foreach ($field->listChildren() as $child) {
            $childData = $this->buildFieldTrait($field->getChild($child), $child);
            if ($childData !== null) {
                $builtData += $childData;
            }
        }

        return $builtData ? $builtData : null;
    }

    /**
     * toStructured の出力に対し、path フィールドの URL 解決と html フィールドの
     * 絶対化（テンプレート出力固有）を適用する。
     *
     * - マルチ項目フィールド (['value' => {...}, 'array' => [...]]) の中の path / html
     * - グループ内マルチ項目（連番キーの行配列の中の各 baseName）の path / html
     *
     * 単一値フィールドや、グループ内単一値フィールドには URL 解決を適用しない（旧挙動）。
     *
     * @param array $data
     * @param Field|Field_Validation $field
     * @return array
     */
    protected function resolveTemplateUrlsTrait(array $data, $field): array
    {
        foreach ($data as $baseName => $entry) {
            if (!is_array($entry) || $entry === []) {
                continue;
            }
            if (array_is_list($entry)) {
                // グループ: 行配列。各行内のマルチ項目エントリに対して URL 解決を適用
                foreach ($entry as $i => $row) {
                    if (!is_array($row)) {
                        continue;
                    }
                    $data[$baseName][$i] = $this->resolveTemplateUrlsInGroupRowTrait($row, $field);
                }
            } elseif (isset($entry['value']) && is_array($entry['value'])) {
                // マルチ項目フィールド: value が連想配列
                $data[$baseName] = $this->resolveTemplateUrlsInMultiEntryTrait($entry, $baseName, $field);
            }
        }
        return $data;
    }

    /**
     * マルチ項目フィールドエントリ（'value'/'array' を持つ）に対して URL 解決を適用。
     *
     * @param array $entry
     * @param string $baseName
     * @param Field|Field_Validation $field
     * @return array
     */
    private function resolveTemplateUrlsInMultiEntryTrait(array $entry, string $baseName, $field): array
    {
        $hasMedia = $field->isExists("{$baseName}@media");
        // value 側
        if (isset($entry['value']['path']) && $entry['value']['path'] !== '' && !$hasMedia) {
            $urlResolver = Application::make('url');
            assert($urlResolver instanceof \Acms\Services\Url\UrlResolver);
            $entry['value']['path'] = $urlResolver->resolveUrl($entry['value']['path'], ARCHIVES_DIR);
        }
        if (isset($entry['value']['html']) && $entry['value']['html'] !== '' && isApiBuildOrV2Module()) {
            $urlResolver = Application::make('url');
            assert($urlResolver instanceof \Acms\Services\Url\UrlResolver);
            $entry['value']['html'] = $urlResolver->convertAssetUrlsToAbsolute($entry['value']['html'], BASE_URL);
        }
        // array 側
        foreach ($entry['array'] ?? [] as $i => $arrayItem) {
            if (!is_array($arrayItem)) {
                continue;
            }
            if (isset($arrayItem['path']) && $arrayItem['path'] !== '' && !$hasMedia) {
                $urlResolver = Application::make('url');
                assert($urlResolver instanceof \Acms\Services\Url\UrlResolver);
                $entry['array'][$i]['path'] = $urlResolver->resolveUrl($arrayItem['path'], ARCHIVES_DIR);
            }
            if (isset($arrayItem['html']) && $arrayItem['html'] !== '' && isApiBuildOrV2Module()) {
                $urlResolver = Application::make('url');
                assert($urlResolver instanceof \Acms\Services\Url\UrlResolver);
                $entry['array'][$i]['html'] = $urlResolver->convertAssetUrlsToAbsolute($arrayItem['html'], BASE_URL);
            }
        }
        return $entry;
    }

    /**
     * グループ内の 1 行に含まれるマルチ項目（連想配列構造）に対して URL 解決を適用。
     *
     * グループ内単一値は ['value' => x] の形なのでスキップ。
     * グループ内マルチ項目は ['alt' => x, 'path' => y, ...] の形。
     *
     * @param array $row
     * @param Field|Field_Validation $field
     * @return array
     */
    private function resolveTemplateUrlsInGroupRowTrait(array $row, $field): array
    {
        foreach ($row as $rowBaseName => $rowEntry) {
            if (!is_array($rowEntry)) {
                continue;
            }
            // 単一値エントリ（'value' / 'invalid' / 'v' 程度の構成）はスキップ
            if (array_key_exists('value', $rowEntry) && count($rowEntry) <= 3) {
                continue;
            }
            if (isset($rowEntry['path']) && $rowEntry['path'] !== '' && !$field->isExists("{$rowBaseName}@media")) {
                $urlResolver = Application::make('url');
                assert($urlResolver instanceof \Acms\Services\Url\UrlResolver);
                $row[$rowBaseName]['path'] = $urlResolver->resolveUrl($rowEntry['path'], ARCHIVES_DIR);
            }
            if (isset($rowEntry['html']) && $rowEntry['html'] !== '' && isApiBuildOrV2Module()) {
                $urlResolver = Application::make('url');
                assert($urlResolver instanceof \Acms\Services\Url\UrlResolver);
                $row[$rowBaseName]['html'] = $urlResolver->convertAssetUrlsToAbsolute($rowEntry['html'], BASE_URL);
            }
        }
        return $row;
    }
}
