<?php

declare(strict_types=1);

namespace app\common\service;

use support\think\Db;
use Throwable;

final class GameRecordService
{
    public const KEY_AUTO_CREATE = 'period_auto_create_enabled';

    public const KEY_MANUAL_CREATE = 'period_manual_create_enabled';

    private const ACTIVE_STATUSES = [0, 1, 2, 3];

    public static function getConfigBool(string $key): bool
    {
        $row = GameHotDataRedis::gameConfigRow($key);
        if (!$row) {
            return false;
        }
        $v = $row['config_value'] ?? '';
        return $v === '1' || $v === 1;
    }

    public static function getRecordSettings(): array
    {
        return [
            'period_auto_create_enabled' => self::getConfigBool(self::KEY_AUTO_CREATE) ? 1 : 0,
            'period_manual_create_enabled' => self::getConfigBool(self::KEY_MANUAL_CREATE) ? 1 : 0,
        ];
    }

    public static function saveRecordSettings(array $data): void
    {
        $now = time();
        $auto = self::truthyConfigInput($data['period_auto_create_enabled'] ?? null) ? '1' : '0';
        $manual = self::truthyConfigInput($data['period_manual_create_enabled'] ?? null) ? '1' : '0';
        self::upsertConfig(self::KEY_AUTO_CREATE, $auto, 'int', '是否允许定时任务自动创建下一局（全局仅一局）', $now);
        self::upsertConfig(self::KEY_MANUAL_CREATE, $manual, 'int', '是否允许后台手动创建下一局', $now);
    }

    public static function hasActiveRecord(): bool
    {
        $count = Db::name('game_record')->whereIn('status', self::ACTIVE_STATUSES)->count();
        return $count > 0;
    }

    public static function tickAutoCreate(): void
    {
        if (!self::getConfigBool(self::KEY_AUTO_CREATE)) {
            return;
        }
        if (self::hasActiveRecord()) {
            return;
        }
        try {
            self::createNextRecordRow();
        } catch (Throwable) {
        }
    }

    public static function createNextRecordForManual(): array
    {
        if (!self::getConfigBool(self::KEY_MANUAL_CREATE)) {
            return ['ok' => false, 'msg' => __('Manual create next round is disabled')];
        }
        if (self::hasActiveRecord()) {
            return ['ok' => false, 'msg' => __('There is an unfinished round; cannot create a new one')];
        }
        try {
            $periodNo = self::createNextRecordRow();
            return ['ok' => true, 'msg' => __('New round created'), 'period_no' => $periodNo];
        } catch (Throwable $e) {
            return ['ok' => false, 'msg' => $e->getMessage()];
        }
    }

    public static function createNextRecordAfterDraw(): ?string
    {
        // 派彩结束后是否自动开新局：由 period_auto_create_enabled 控制
        if (!self::getConfigBool(self::KEY_AUTO_CREATE)) {
            return null;
        }
        if (self::hasActiveRecord()) {
            return null;
        }
        return self::createNextRecordRow();
    }

    /**
     * 实时对局页「自动创建下一局」开关（兼容旧命名 runtime）。
     */
    public static function isLiveRuntimeEnabled(): bool
    {
        return self::getConfigBool(self::KEY_AUTO_CREATE);
    }

    public static function setLiveRuntimeEnabled(bool $enabled): void
    {
        self::setAutoCreateEnabled($enabled);
    }

    /**
     * 重新开启游戏时：若无进行中/未结清对局，则立即创建新一期（与定时任务「无局时自动创建」语义一致，供开关打开时立刻开局）。
     */
    public static function bootstrapPeriodWhenRuntimeEnabled(): void
    {
        if (!self::getConfigBool(self::KEY_AUTO_CREATE)) {
            return;
        }
        if (self::hasActiveRecord()) {
            return;
        }
        try {
            self::createNextRecordRow();
        } catch (Throwable) {
        }
    }

    public static function setAutoCreateEnabled(bool $enabled): void
    {
        $now = time();
        $v = $enabled ? '1' : '0';
        self::upsertConfig(self::KEY_AUTO_CREATE, $v, 'int', '是否允许自动创建下一局（全局仅一局）', $now);
    }

    private static function createNextRecordRow(): string
    {
        $periodNo = self::generatePeriodNo();
        $now = time();
        Db::name('game_record')->insert([
            'period_no' => $periodNo,
            'period_start_at' => $now,
            'status' => 0,
            'draw_mode' => 0,
            'void_reason' => '',
            'create_time' => $now,
            'update_time' => $now,
        ]);
        GameHotDataCoordinator::afterGameRecordCommitted(null);
        return $periodNo;
    }

    private static function generatePeriodNo(): string
    {
        return date('Ymd-His') . '-' . substr(bin2hex(random_bytes(4)), 0, 8);
    }

    private static function truthyConfigInput(mixed $v): bool
    {
        return $v === 1 || $v === '1' || $v === true;
    }

    private static function upsertConfig(string $key, string $value, string $valueType, string $remark, int $now): void
    {
        $exists = Db::name('game_config')->where('config_key', $key)->find();
        if ($exists) {
            Db::name('game_config')->where('config_key', $key)->update([
                'config_value' => $value,
                'value_type' => $valueType,
                'remark' => $remark,
                'update_time' => $now,
            ]);
            GameHotDataCoordinator::afterGameConfigKeyCommitted($key);
            return;
        }
        Db::name('game_config')->insert([
            'config_key' => $key,
            'config_value' => $value,
            'value_type' => $valueType,
            'remark' => $remark,
            'create_time' => $now,
            'update_time' => $now,
        ]);
        GameHotDataCoordinator::afterGameConfigKeyCommitted($key);
    }
}
