<?php

declare(strict_types=1);

namespace app\common\library\game;

use InvalidArgumentException;

/**
 * 充值档位（game_config.deposit_tier）：仅存 JSON 数组
 *
 * 每一项字段（mock/第三方支付模式，已不再保存收款账户信息；支持中英文双语）：
 *   - id            : string，档位稳定唯一标识（如 t_xxxxxxxx），移动端下单 tier_id / tier_key
 *   - title         : string，档位中文名称（必填，前端中文环境展示）
 *   - title_en      : string，档位英文名称（可选，前端英文环境展示；为空时回退到 title）
 *   - currency      : string，支付货币代码（3～8 位大写字母，如 MYR、CNY）
 *   - pay_amount    : string，玩家支付的法币/支付货币额度（2 位小数）
 *   - amount        : string，到账基础平台币（2 位小数）
 *   - bonus_amount  : string，赠送平台币（2 位小数，可为 0）
 *   - desc          : string，档位中文描述（可空，<=255）
 *   - desc_en       : string，档位英文描述（可空，<=255，为空时回退到 desc）
 *   - sort          : int，排序权重（小值在前）
 *   - status        : int，0=停用，1=启用
 *
 * 历史数据兼容：老字段 name 会在 title 缺失时作为 title 兜底（更老的 account_name 亦会兜底）。
 */
final class DepositTier
{
    public const CONFIG_KEY = 'deposit_tier';

    /**
     * 从 game_config.config_value 中解析出档位数组（容错）
     *
     * @return list<array{
     *     id: string,
     *     title: string,
     *     title_en: string,
     *     currency: string,
     *     pay_amount: string,
     *     amount: string,
     *     bonus_amount: string,
     *     desc: string,
     *     desc_en: string,
     *     sort: int,
     *     status: int,
     * }>
     */
    public static function parseFromConfigValue($raw): array
    {
        if (!is_string($raw) || trim($raw) === '') {
            return [];
        }
        $decoded = json_decode($raw, true);
        if (!is_array($decoded)) {
            return [];
        }
        if (isset($decoded['tiers']) && is_array($decoded['tiers'])) {
            $list = $decoded['tiers'];
        } else {
            $list = $decoded;
        }
        return self::normalizeList($list);
    }

    /**
     * @param list<mixed> $items
     */
    public static function normalizeList(array $items): array
    {
        $out = [];
        foreach ($items as $row) {
            if (!is_array($row)) {
                continue;
            }
            $id = isset($row['id']) && is_string($row['id']) ? trim($row['id']) : '';
            if ($id === '') {
                $id = self::generateId();
            }

            $title = self::stringField($row, 'title');
            if ($title === '') {
                // 兼容历史：字段名 name 或更老的 account_name
                $title = self::stringField($row, 'name');
                if ($title === '') {
                    $title = self::stringField($row, 'account_name');
                }
            }
            $titleEn = self::stringField($row, 'title_en');

            $currency = self::normalizeCurrency($row['currency'] ?? '');
            if ($currency === '') {
                $currency = 'CNY';
            }

            $payAmount = self::normalizeAmount($row['pay_amount'] ?? '');
            $amount = self::normalizeAmount($row['amount'] ?? '');
            $bonus = self::normalizeAmount($row['bonus_amount'] ?? '0');
            if (bccomp($payAmount, '0', 2) <= 0 && bccomp($amount, '0', 2) > 0) {
                // 历史数据仅有 amount（平台币）时，用占位同步 pay_amount，运营应在后台改为真实支付额度
                $payAmount = $amount;
            }

            $desc = self::stringField($row, 'desc');
            if ($desc === '') {
                $desc = self::stringField($row, 'remark');
            }
            $descEn = self::stringField($row, 'desc_en');

            $sort = isset($row['sort']) && is_numeric($row['sort']) ? intval($row['sort']) : 0;
            $status = isset($row['status']) && is_numeric($row['status']) ? intval($row['status']) : 1;
            $status = $status === 1 ? 1 : 0;

            $out[] = [
                'id'           => $id,
                'title'        => $title,
                'title_en'     => $titleEn,
                'currency'     => $currency,
                'pay_amount'   => $payAmount,
                'amount'       => $amount,
                'bonus_amount' => $bonus,
                'desc'         => $desc,
                'desc_en'      => $descEn,
                'sort'         => $sort,
                'status'       => $status,
            ];
        }
        usort($out, static function (array $a, array $b): int {
            if ($a['sort'] !== $b['sort']) {
                return $a['sort'] <=> $b['sort'];
            }
            $ida = is_string($a['id']) ? $a['id'] : '';
            $idb = is_string($b['id']) ? $b['id'] : '';
            return strcmp($ida, $idb);
        });
        return $out;
    }

    /**
     * 校验 POST 数据并输出用于入库的清洁数据
     *
     * @param list<array<string, mixed>> $items
     *
     * @throws InvalidArgumentException
     */
    public static function prepareItemsForSave(array $items): array
    {
        $seenId = [];
        $out = [];
        foreach ($items as $idx => $row) {
            $no = $idx + 1;
            if (!is_array($row)) {
                throw new InvalidArgumentException('Row format error');
            }

            $id = isset($row['id']) && is_string($row['id']) ? trim($row['id']) : '';
            if ($id === '') {
                $id = self::generateId();
            }
            if (!preg_match('/^[a-zA-Z0-9_\-]{1,32}$/', $id)) {
                throw new InvalidArgumentException('Tier id is invalid');
            }
            if (isset($seenId[$id])) {
                throw new InvalidArgumentException('Duplicate tier id');
            }
            $seenId[$id] = true;

            $title = self::stringField($row, 'title');
            if ($title === '') {
                // 兼容上游（例如自动迁移脚本）传递历史 name 字段
                $title = self::stringField($row, 'name');
            }
            if ($title === '') {
                throw new InvalidArgumentException('Tier title (zh) is required');
            }
            if (mb_strlen($title) > 64) {
                throw new InvalidArgumentException('Tier title (zh) is too long');
            }

            $titleEn = self::stringField($row, 'title_en');
            if (mb_strlen($titleEn) > 64) {
                throw new InvalidArgumentException('Tier title (en) is too long');
            }

            $currency = self::normalizeCurrency($row['currency'] ?? '');
            if ($currency === '') {
                throw new InvalidArgumentException('Currency is required');
            }

            $payAmount = self::normalizeAmount($row['pay_amount'] ?? '');
            if (bccomp($payAmount, '0', 2) <= 0) {
                throw new InvalidArgumentException('Pay amount must be greater than 0');
            }

            $amount = self::normalizeAmount($row['amount'] ?? '');
            if (bccomp($amount, '0', 2) <= 0) {
                throw new InvalidArgumentException('Base credit amount must be greater than 0');
            }

            $bonus = self::normalizeAmount($row['bonus_amount'] ?? '0');
            if (bccomp($bonus, '0', 2) < 0) {
                throw new InvalidArgumentException('Bonus amount cannot be negative');
            }

            $desc = self::stringField($row, 'desc');
            if (mb_strlen($desc) > 255) {
                throw new InvalidArgumentException('Description (zh) is too long');
            }

            $descEn = self::stringField($row, 'desc_en');
            if (mb_strlen($descEn) > 255) {
                throw new InvalidArgumentException('Description (en) is too long');
            }

            $sort = isset($row['sort']) && is_numeric($row['sort']) ? intval($row['sort']) : 0;
            $statusRaw = isset($row['status']) && is_numeric($row['status']) ? intval($row['status']) : 1;
            $status = $statusRaw === 1 ? 1 : 0;

            $out[] = [
                'id'           => $id,
                'title'        => $title,
                'title_en'     => $titleEn,
                'currency'     => $currency,
                'pay_amount'   => $payAmount,
                'amount'       => $amount,
                'bonus_amount' => $bonus,
                'desc'         => $desc,
                'desc_en'      => $descEn,
                'sort'         => $sort,
                'status'       => $status,
            ];
        }

        usort($out, static function (array $a, array $b): int {
            if ($a['sort'] !== $b['sort']) {
                return $a['sort'] <=> $b['sort'];
            }
            $ida = is_string($a['id']) ? $a['id'] : '';
            $idb = is_string($b['id']) ? $b['id'] : '';
            return strcmp($ida, $idb);
        });
        return $out;
    }

    /**
     * @param list<array<string, mixed>> $items
     */
    public static function encodeForDb(array $items): string
    {
        $encoded = json_encode($items, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        if ($encoded === false) {
            throw new InvalidArgumentException('JSON encode failed');
        }
        return $encoded;
    }

    /**
     * 过滤出启用档位并按 sort 升序，供移动端选择
     */
    public static function publicList(array $items): array
    {
        $enabled = array_values(array_filter($items, static function (array $row): bool {
            if (!isset($row['status'])) {
                return false;
            }
            $val = is_numeric($row['status']) ? intval($row['status']) : 0;
            return $val === 1;
        }));
        usort($enabled, static function (array $a, array $b): int {
            $sa = isset($a['sort']) && is_numeric($a['sort']) ? intval($a['sort']) : 0;
            $sb = isset($b['sort']) && is_numeric($b['sort']) ? intval($b['sort']) : 0;
            if ($sa !== $sb) {
                return $sa <=> $sb;
            }
            $ida = isset($a['id']) && is_string($a['id']) ? $a['id'] : '';
            $idb = isset($b['id']) && is_string($b['id']) ? $b['id'] : '';
            return strcmp($ida, $idb);
        });
        return $enabled;
    }

    /**
     * 按 ID 从档位列表中取出指定档位；未找到返回 null
     */
    public static function findById(array $items, string $id): ?array
    {
        foreach ($items as $row) {
            if (!is_array($row)) {
                continue;
            }
            $rid = $row['id'] ?? '';
            if (is_string($rid) && $rid === $id) {
                return $row;
            }
        }
        return null;
    }

    /**
     * 根据语言选择档位对外展示的 title/desc。
     *
     * @param array<string, mixed> $item
     * @return array{title: string, desc: string}
     */
    public static function localize(array $item, string $lang): array
    {
        $title = self::stringField($item, 'title');
        $titleEn = self::stringField($item, 'title_en');
        $desc = self::stringField($item, 'desc');
        $descEn = self::stringField($item, 'desc_en');

        $isEn = self::isEnglishLang($lang);
        $pickedTitle = $isEn ? ($titleEn !== '' ? $titleEn : $title) : ($title !== '' ? $title : $titleEn);
        $pickedDesc = $isEn ? ($descEn !== '' ? $descEn : $desc) : ($desc !== '' ? $desc : $descEn);

        return [
            'title' => $pickedTitle,
            'desc'  => $pickedDesc,
        ];
    }

    /**
     * 生成 10 位稳定 ID（t_ + 8 位随机 base32）
     */
    public static function generateId(): string
    {
        $chars = 'abcdefghijkmnpqrstuvwxyz23456789';
        $len = strlen($chars);
        $id = 't_';
        for ($i = 0; $i < 8; $i++) {
            $id .= $chars[random_int(0, $len - 1)];
        }
        return $id;
    }

    /**
     * 将金额归一化为 2 位小数字符串；非法输入返回 '0.00'
     */
    public static function normalizeAmount($raw): string
    {
        if ($raw === null || $raw === '') {
            return '0.00';
        }
        if (is_string($raw)) {
            $s = trim($raw);
        } elseif (is_int($raw) || is_float($raw)) {
            $s = strval($raw);
        } else {
            return '0.00';
        }
        $s = str_replace(',', '.', $s);
        if (!is_numeric($s)) {
            return '0.00';
        }
        return bcadd($s, '0', 2);
    }

    /**
     * 从数组取字符串字段并 trim，非字符串返回空串
     *
     * @param array<string, mixed> $row
     */
    private static function stringField(array $row, string $key): string
    {
        if (!isset($row[$key])) {
            return '';
        }
        $v = $row[$key];
        return is_string($v) ? trim($v) : '';
    }

    /**
     * 支付货币代码：3～8 位字母，统一大写
     *
     * @param mixed $raw
     */
    private static function normalizeCurrency($raw): string
    {
        if (!is_string($raw)) {
            return '';
        }
        $s = strtoupper(trim($raw));
        if ($s === '') {
            return '';
        }
        if (!preg_match('/^[A-Z]{3,8}$/', $s)) {
            return '';
        }
        return $s;
    }

    private static function isEnglishLang(string $lang): bool
    {
        $normalized = strtolower(str_replace('_', '-', trim($lang)));
        if ($normalized === '') {
            return false;
        }
        return $normalized === 'en' || str_starts_with($normalized, 'en-');
    }
}
