<?php

namespace Acms\Services\Update;

use Acms\Contracts\ServiceProvider;
use Acms\Services\Container;
use Acms\Services\Common\Lock;
use Acms\Services\Facades\Logger as AcmsLogger;

class UpdateServiceProvider extends ServiceProvider
{
    /**
     * system_update_repository が未設定・空・非文字列の場合のフォールバック先。
     * config.system.default.yaml の既定値と同じ値にしている。
     */
    private const DEFAULT_REPOSITORY_URL = 'https://www.a-blogcms.jp/api/update.json';

    /**
     * register service
     *
     * @param \Acms\Services\Container $container
     *
     * @return void
     */
    public function register(Container $container)
    {
        $cache = SCRIPT_DIR . CACHE_DIR . 'update.json';
        $schema = LIB_DIR . 'Services/Update/template/schema.json';

        $container->singleton('update.exec.update', \Acms\Services\Update\Operations\Update::class);
        $container->singleton('update.exec.downgrade', \Acms\Services\Update\Operations\Downgrade::class);
        $container->singleton('update.lock', function () {
            return new Lock(SCRIPT_DIR . CACHE_DIR . 'system-update-lock');
        });
        $container->singleton('update.logger', \Acms\Services\Update\LoggerFactory::class);
        $container->singleton('update.check', function () use ($cache, $schema) {
            return new System\CheckForUpdate($this->resolveRepositoryUrl(), $cache, $schema);
        });
    }

    /**
     * system_update_repository の設定値を取得する。
     *
     * Why not: config.system.default.yaml の既定値を https に変えるだけでは済ませられない。
     * private/config.system.yaml（差し替え対象外）や DB コンフィグにすでに http:// の値が
     * 保存されている環境には既定値の変更が反映されないため、ここで読み替える。
     *
     * Why not: config() の第2引数（デフォルト値）に self::DEFAULT_REPOSITORY_URL を渡している。
     * Field::get() は該当キーが未設定・空文字・型不正のいずれでも渡した既定値を採用したうえで
     * 必ず string にキャストして返す実装のため、is_string() による分岐は不要（分岐を書くと
     * config() の PHPDoc 型（文字列キーでは string に縮退）により PHPStan には常に true と
     * 判定され静的解析の抑制コメントが要る。この既定値渡しならその抑制自体が要らない）。
     *
     * @return string
     */
    private function resolveRepositoryUrl(): string
    {
        $repositoryUrl = config('system_update_repository', self::DEFAULT_REPOSITORY_URL);

        $resolvedRepositoryUrl = System\RepositoryUrl::enforceHttps($repositoryUrl);
        if ($resolvedRepositoryUrl === $repositoryUrl) {
            return $repositoryUrl;
        }

        AcmsLogger::notice(
            'システム更新の取得先URL（system_update_repository）がhttp://だったためhttps://に読み替えました',
            ['original' => $repositoryUrl, 'resolved' => $resolvedRepositoryUrl]
        );

        return $resolvedRepositoryUrl;
    }

    /**
     * initialize service
     *
     * @return void
     */
    public function init()
    {
    }
}
