<?php
/**
 * VR票务插件 - 座位 SKU 服务
 *
 * ShopXO 规格表结构：
 *   GoodsSpecType  : id, goods_id, name, value(JSON数组), add_time
 *   GoodsSpecBase  : id, goods_id, price, original_price, inventory, ...
 *   GoodsSpecValue : id, goods_id, goods_spec_base_id, value, md5_key, add_time
 *
 * 列对应关系由 GoodsEditSpecifications 决定：
 *   它把每个 GoodsSpecValue.value 逐个在 GoodsSpecType.value(JSON) 的 name 字段中搜索，
 *   匹配成功才显示在对应列。
 *   因此：GoodsSpecType.value JSON 里必须包含我们写入的所有 value 字符串。
 *
 * @package vr_ticket\service
 */

namespace app\plugins\vr_ticket\service;

use think\facade\Db;
require_once __DIR__ . '/BaseService.php';

class SeatSkuService extends BaseService
{
    const BATCH_SIZE = 200;

    /**
     * VR 规格维度名（顺序固定，5维）
     * 注意：按选购流程顺序排列：场次 → 场馆 → 演播室 → 分区 → 座位号
     */
    const SPEC_DIMS = ['$vr-场次', '$vr-场馆', '$vr-演播室', '$vr-分区', '$vr-座位号'];

    /**
     * 批量生成座位级 SKU
     *
     * @param int    $goodsId
     * @param int    $seatTemplateId
     * @param array  $selectedRooms     要生成的厅 id 列表，空=全部
     * @param array  $selectedSections  按 roomId 为 key 的分区 char 数组，空=全部
     * @param array  $sessions          场次数组 e.g. [["start"=>"08:00","end"=>"23:59"]]
     */
    public static function BatchGenerate(
        int   $goodsId,
        int   $seatTemplateId,
        array $selectedRooms    = [],
        array $selectedSections = [],
        array $sessions         = []
    ): array {
        if ($goodsId <= 0 || $seatTemplateId <= 0) {
            return ['code' => -1, 'msg' => '参数错误：goodsId 或 seatTemplateId 无效'];
        }

        // 1. 加载座位模板
        $template = Db::name(self::table('seat_templates'))
            ->where('id', $seatTemplateId)
            ->find();
        if (empty($template)) {
            return ['code' => -2, 'msg' => "座位模板 {$seatTemplateId} 不存在"];
        }

        // 2. 解析 seat_map
        $seatMap = json_decode($template['seat_map'] ?? '{}', true);
        $rooms   = $seatMap['rooms'] ?? [];
        if (empty($rooms)) {
            return ['code' => -3, 'msg' => '座位模板 seat_map 无效（rooms 为空）'];
        }

        // 使用模板表的短名称
        $venueName = $template['name'] ?? '未命名场馆';

        // 3. 场次处理（默认兜底）
        if (empty($sessions)) {
            $sessions = [['start' => '08:00', 'end' => '23:59']];
        }
        $sessionStrings = [];
        foreach ($sessions as $s) {
            $start = is_array($s) ? ($s['start'] ?? '08:00') : '08:00';
            $end   = is_array($s) ? ($s['end']   ?? '23:59') : '23:59';
            $sessionStr = "{$start}-{$end}";
            if (!in_array($sessionStr, $sessionStrings)) {
                $sessionStrings[] = $sessionStr;
            }
        }

        // 4. 确保 4 个 VR spec type 维度存在，同时收集要写入的所有唯一 value
        //    我们先遍历座位图，收集全部规格值，再一次性写入 type.value JSON
        $selectedRooms    = array_values(array_filter($selectedRooms));
        $selectedSections = array_filter($selectedSections);

        // 按维度收集唯一值（用 有序列表 + 去重）
        $dimUniqueValues = [
            '$vr-场次'  => [],
            '$vr-场馆'  => [],
            '$vr-演播室' => [],
            '$vr-分区'  => [],
            '$vr-座位号' => [],
        ];

        // 5. 遍历地图，收集所有座位信息
        $seatsToInsert = [];
        foreach ($rooms as $rIdx => $room) {
            // 与前端 PHP 预处理保持一致：id 缺失时用 'room_{index}'
            $roomId   = !empty($room['id']) ? $room['id'] : ('room_' . $rIdx);
            $roomName = $room['name'] ?? '默认放映室';

            if (!empty($selectedRooms) && !in_array($roomId, $selectedRooms)) {
                continue;
            }

            // char → price 映射
            $sectionPrices = [];
            foreach (($room['sections'] ?? []) as $sec) {
                if (!empty($sec['char'])) {
                    $sectionPrices[$sec['char']] = floatval($sec['price'] ?? 0);
                }
            }

            $map       = $room['map']   ?? [];
            $seatsData = $room['seats'] ?? [];

            foreach ($map as $rowIndex => $rowStr) {
                $rowLabel = chr(65 + $rowIndex);
                $chars    = mb_str_split($rowStr);

                foreach ($chars as $colIndex => $char) {
                    if ($char === '_' || $char === '-' || !isset($seatsData[$char])) {
                        continue;
                    }

                    if (!empty($selectedSections[$roomId])
                        && !in_array($char, $selectedSections[$roomId])) {
                        continue;
                    }

                    // 价格三级 fallback
                    $seatInfo  = $seatsData[$char];
                    $seatPrice = floatval($seatInfo['price'] ?? 0);
                    if ($seatPrice == 0 && isset($sectionPrices[$char])) {
                        $seatPrice = $sectionPrices[$char];
                    }
                    if ($seatPrice == 0) {
                        foreach (($room['sections'] ?? []) as $sec) {
                            if (($sec['char'] ?? '') === $char) {
                                $seatPrice = floatval($sec['price'] ?? 0);
                                break;
                            }
                        }
                    }

                    $col = $colIndex + 1;

                    // 维度值字符串（确保非空）
                    $val_venue   = $venueName;
                    $val_section = $venueName . '-' . $roomName . '-' . $char;
                    $val_seat    = $venueName . '-' . $roomName . '-' . $char . '-' . $rowLabel . $col;

                    foreach ($sessionStrings as $sessionStr) {
                        $seatKey = $roomId . '_' . $rowLabel . '_' . $col;
                        $seatId = $seatKey . '_' . md5($sessionStr);

                        $seatsToInsert[$seatId] = [
                            'price'       => $seatPrice,
                            'seat_key'    => $seatKey,  // ← 用于前端映射
                            'extends'     => json_encode(['seat_key' => $seatKey], JSON_UNESCAPED_UNICODE),
                            'spec_values' => [
                                $sessionStr,     // $vr-场次（第1维）
                                $val_venue,      // $vr-场馆（第2维）
                                $roomName,       // $vr-演播室（第3维）
                                $val_section,    // $vr-分区（第4维）
                                $val_seat,       // $vr-座位号（第5维）
                            ],
                        ];

                        // 收集唯一维度值（保持首次出现顺序，与 SPEC_DIMS 对应）
                        if (!in_array($sessionStr, $dimUniqueValues['$vr-场次'])) {
                            $dimUniqueValues['$vr-场次'][] = $sessionStr;
                        }
                        if (!in_array($val_venue, $dimUniqueValues['$vr-场馆'])) {
                            $dimUniqueValues['$vr-场馆'][] = $val_venue;
                        }
                        if (!in_array($roomName, $dimUniqueValues['$vr-演播室'])) {
                            $dimUniqueValues['$vr-演播室'][] = $roomName;
                        }
                        if (!in_array($val_section, $dimUniqueValues['$vr-分区'])) {
                            $dimUniqueValues['$vr-分区'][] = $val_section;
                        }
                        if (!in_array($val_seat, $dimUniqueValues['$vr-座位号'])) {
                            $dimUniqueValues['$vr-座位号'][] = $val_seat;
                        }
                    }
                }
            }
        }

        if (empty($seatsToInsert)) {
            return ['code' => -4, 'msg' => '无有效座位可生成'];
        }

        // 6. 保证 4 个 VR spec type 存在，并把已收集的 value 写入 type.value JSON
        //    这样 GoodsEditSpecifications 的 name 匹配才能命中每条 GoodsSpecValue
        self::ensureAndFillVrSpecTypes($goodsId, $dimUniqueValues);

        // 7. 写入 GoodsSpecBase + GoodsSpecValue
        $now            = time();
        $generatedCount = 0;
        $valueBatch     = [];

        foreach ($seatsToInsert as $seatId => $s) {
            $baseId = Db::name('GoodsSpecBase')->insertGetId([
                'goods_id'       => $goodsId,
                'price'          => $s['price'],
                'original_price' => 0,
                'inventory'      => 1,
                'buy_min_number' => 1,
                'buy_max_number' => 1,
                'weight'         => 0,
                'volume'         => 0,
                'coding'         => '',
                'barcode'        => '',
                'add_time'       => $now,
                'extends'        => $s['extends'] ?? null,
            ]);

            if (!$baseId) {
                throw new \Exception("GoodsSpecBase 写入失败 (seat: {$seatId})");
            }

            // 5 条 GoodsSpecValue，每条对应一个维度（按 SPEC_DIMS 顺序）
            // 注意：GoodsSpecValue 表没有 name 字段，只能通过 value 匹配关联维度
            foreach ($s['spec_values'] as $specVal) {
                $valueBatch[] = [
                    'goods_id'           => $goodsId,
                    'goods_spec_base_id' => $baseId,
                    'value'              => (string)$specVal,
                    'md5_key'            => md5((string)$specVal),
                    'add_time'           => $now,
                ];
            }

            $generatedCount++;

            if (count($valueBatch) >= self::BATCH_SIZE) {
                Db::name('GoodsSpecValue')->insertAll($valueBatch);
                $valueBatch = [];
            }
        }

        if (!empty($valueBatch)) {
            Db::name('GoodsSpecValue')->insertAll($valueBatch);
        }

        return [
            'code' => 0,
            'msg'  => '生成成功',
            'data' => [
                'total'     => count($seatsToInsert),
                'generated' => $generatedCount,
            ],
        ];
    }

    /**
     * 幂等确保 4 个 VR 维度存在，并把本次收集的所有唯一值合并写入 type.value JSON
     *
     * 关键：GoodsEditSpecifications 通过 type.value JSON 里的 name 做匹配，
     * 所以每条 GoodsSpecValue.value 都必须在对应 type.value 的某个 name 里找到。
     *
     * @param int   $goodsId
     * @param array $dimUniqueValues  ['$vr-场馆' => [...], '$vr-分区' => [...], ...]
     */
    public static function ensureAndFillVrSpecTypes(int $goodsId, array $dimUniqueValues = []): void
    {
        $now = time();

        // 读取已存在的 VR 维度（按顺序）
        $existing = Db::name('GoodsSpecType')
            ->where('goods_id', $goodsId)
            ->whereIn('name', self::SPEC_DIMS)
            ->order('id', 'asc')
            ->select()
            ->toArray();

        $existingByName = array_column($existing, null, 'name');

        foreach (self::SPEC_DIMS as $dimName) {
            // 构建该维度的 value JSON（把所有唯一值合并，含已有值）
            $newItems = [];
            $existingItems = [];
            if (isset($existingByName[$dimName])) {
                $existingItems = json_decode($existingByName[$dimName]['value'] ?? '[]', true);
                if (!is_array($existingItems)) $existingItems = [];
            }

            // 把现有 JSON 中的 name 提取出来
            $existingNames = array_column($existingItems, 'name');

            // 合并本次新增的值
            $toAdd = $dimUniqueValues[$dimName] ?? [];
            foreach ($toAdd as $val) {
                if (!in_array($val, $existingNames)) {
                    $existingItems[] = ['name' => (string)$val, 'images' => ''];
                    $existingNames[] = $val;
                }
            }

            $valueJson = json_encode($existingItems, JSON_UNESCAPED_UNICODE);

            if (isset($existingByName[$dimName])) {
                // 更新已有维度的 value JSON
                Db::name('GoodsSpecType')
                    ->where('id', $existingByName[$dimName]['id'])
                    ->update(['value' => $valueJson]);
            } else {
                // 插入缺失维度（保持 SPEC_DIMS 顺序，ID 递增）
                Db::name('GoodsSpecType')->insert([
                    'goods_id' => $goodsId,
                    'name'     => $dimName,
                    'value'    => $valueJson,
                    'add_time' => $now,
                ]);
            }
        }
    }

    /**
     * 重新计算商品基础信息（价格区间、总库存）
     */
    public static function refreshGoodsBase(int $goodsId): array
    {
        $bases = Db::name('GoodsSpecBase')
            ->where('goods_id', $goodsId)
            ->select()
            ->toArray();

        if (empty($bases)) {
            return ['code' => -1, 'msg' => '无 GoodsSpecBase'];
        }

        $prices    = array_column($bases, 'price');
        $minPrice  = min($prices);
        $maxPrice  = max($prices);
        $inventory = array_sum(array_column($bases, 'inventory'));

        $priceDisplay = ($minPrice != $maxPrice && $maxPrice > 0)
            ? $minPrice . '-' . $maxPrice : $minPrice;

        Db::name('Goods')->where('id', $goodsId)->update([
            'min_price'          => $minPrice,
            'max_price'          => $maxPrice,
            'price'              => $priceDisplay,
            'min_original_price' => 0,
            'max_original_price' => 0,
            'original_price'     => 0,
            'inventory'          => $inventory,
            'is_exist_many_spec' => 1,
            'buy_min_number'     => 1,
            'buy_max_number'     => 1,
            'upd_time'           => time(),
        ]);

        return ['code' => 0];
    }

    /**
     * 获取商品前端展示数据（供 ticket_detail.html 模板使用）
     *
     * @param int $goodsId
     * @return array ['vr_seat_template' => [...], 'goods_spec_data' => [], 'seatSpecMap' => [...]]
     */
    public static function GetGoodsViewData(int $goodsId): array
    {
        // 读取 vr_goods_config
        $goods = \think\facade\Db::name('goods')->find($goodsId);
        $vrGoodsConfig = json_decode($goods['vr_goods_config'] ?? '', true);

        if (empty($vrGoodsConfig) || !is_array($vrGoodsConfig)) {
            return ['vr_seat_template' => null, 'goods_spec_data' => [], 'seatSpecMap' => [], 'goods_config' => null];
        }

        // 过滤有效配置块（多模板模式）
        $validConfigs = [];
        foreach ($vrGoodsConfig as $cfg) {
            $tid = intval($cfg['template_id'] ?? 0);
            if ($tid <= 0) continue;
            $tpl = \think\facade\Db::name(self::table('seat_templates'))->where('id', $tid)->find();
            if (!empty($tpl)) {
                $validConfigs[] = $cfg;
            }
        }
        if (empty($validConfigs)) {
            return ['vr_seat_template' => null, 'goods_spec_data' => [], 'seatSpecMap' => [], 'goods_config' => null];
        }

        // 取第一个有效配置块用于前端展示
        $config = $validConfigs[0];
        $templateId = intval($config['template_id'] ?? 0);
        if ($templateId <= 0) {
            return ['vr_seat_template' => null, 'goods_spec_data' => [], 'seatSpecMap' => [], 'goods_config' => null];
        }

        // 读取座位模板（包含 seat_map 和 spec_base_id_map）
        $seatTemplate = \think\facade\Db::name(self::table('seat_templates'))
            ->where('id', $templateId)
            ->find();

        // 模板不存在时（硬删除场景）：清理无效配置块，写回有效配置
        if (empty($seatTemplate)) {
            $validConfigs = array_filter($validConfigs, function ($cfg) use ($templateId) {
                $tid = intval($cfg['template_id'] ?? 0);
                if ($tid <= 0 || $tid === $templateId) return false;
                $tpl = \think\facade\Db::name(self::table('seat_templates'))->where('id', $tid)->find();
                return !empty($tpl);
            });
            $validConfigs = array_values($validConfigs);
            if (!empty($validConfigs)) {
                \think\facade\Db::name('Goods')->where('id', $goodsId)->update([
                    'vr_goods_config' => json_encode($validConfigs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                ]);
            } else {
                \think\facade\Db::name('Goods')->where('id', $goodsId)->update(['vr_goods_config' => '']);
            }
            return ['vr_seat_template' => null, 'goods_spec_data' => [], 'seatSpecMap' => [], 'goods_config' => null];
        }

        // 解码 seat_map JSON（存储时是 JSON 字符串）
        if (!empty($seatTemplate['seat_map'])) {
            $decoded = json_decode($seatTemplate['seat_map'], true);
            if (json_last_error() === JSON_ERROR_NONE) {
                $seatTemplate['seat_map'] = $decoded;
            }
        }

        // ========== 构建规格类型列表（4维：场馆、分区、座位号、场次）==========
        // 从 GoodsSpecType 读取所有维度定义
        $specTypeList = [];
        $specTypes = \think\facade\Db::name('GoodsSpecType')
            ->where('goods_id', $goodsId)
            ->order('id', 'asc')
            ->select()
            ->toArray();

        foreach ($specTypes as $type) {
            $dimName = $type['name'] ?? '';
            $values = json_decode($type['value'] ?? '[]', true);
            $options = [];
            foreach ($values as $v) {
                if (isset($v['name'])) {
                    $options[] = $v['name'];
                }
            }
            if (!empty($dimName) && !empty($options)) {
                $specTypeList[$dimName] = [
                    'name'    => $dimName,
                    'options' => $options,
                ];
            }
        }

        // ========== 构建 seatSpecMap ==========
        $seatSpecMap = self::buildSeatSpecMap($goodsId, $seatTemplate);

        // ========== 构建场次列表（goods_spec_data）==========
        $sessions = $config['sessions'] ?? [];
        $goodsSpecData = [];

        foreach ($sessions as $session) {
            $start = $session['start'] ?? '';
            $end = $session['end'] ?? '';
            $timeRange = $start && $end ? "{$start}-{$end}" : ($start ?: $end);

            // 查找该场次对应的最低价格（从 seatSpecMap 中获取）
            $sessionPrice = null;
            foreach ($seatSpecMap as $seatKey => $info) {
                foreach ($info['spec'] as $specItem) {
                    $specType = $specItem['type'] ?? '';
                    $specValue = $specItem['value'] ?? '';
                    if ($specType === '$vr-场次' && $specValue === $timeRange) {
                        if ($sessionPrice === null || $info['price'] < $sessionPrice) {
                            $sessionPrice = $info['price'];
                        }
                        break 2;
                    }
                }
            }

            $goodsSpecData[] = [
                'spec_id'   => 0,
                'spec_name' => $timeRange,
                'price'     => $sessionPrice ?? floatval($goods['price'] ?? 0),
                'start'     => $start,
                'end'       => $end,
            ];
        }

        // 如果没有从配置读取到场次，尝试从 seatSpecMap 提取唯一场次
        if (empty($goodsSpecData)) {
            $sessionMap = [];
            foreach ($seatSpecMap as $info) {
                foreach ($info['spec'] as $specItem) {
                    $specType = $specItem['type'] ?? '';
                    if ($specType === '$vr-场次') {
                        $sessionMap[$specItem['value'] ?? ''] = $specItem['value'] ?? '';
                    }
                }
            }
            foreach ($sessionMap as $timeRange) {
                $goodsSpecData[] = [
                    'spec_id'   => 0,
                    'spec_name' => $timeRange,
                    'price'     => floatval($goods['price'] ?? 0),
                    'start'     => '',
                    'end'       => '',
                ];
            }
        }

        return [
            'vr_seat_template' => $seatTemplate ?: null,
            'goods_spec_data'  => $goodsSpecData,
            'seatSpecMap'      => $seatSpecMap,
            'specTypeList'     => $specTypeList,  // 4维规格类型列表
            'goods_config'     => $config,
        ];
    }

    /**
     * 构建座位规格映射表（seatSpecMap）
     *
     * @param int   $goodsId
     * @param array $seatTemplate
     * @return array seatSpecMap
     */
    private static function buildSeatSpecMap(int $goodsId, array $seatTemplate): array
    {
        $seatSpecMap = [];

        // 1. 查询当前商品所有 GoodsSpecBase（含 extends.seat_key）
        $specs = \think\facade\Db::name('GoodsSpecBase')
            ->where('goods_id', $goodsId)
            ->where('inventory', '>', 0)
            ->select()
            ->toArray();

        if (empty($specs)) {
            return $seatSpecMap;
        }

        // 2. 查询 GoodsSpecType 获取维度映射（name => index）
        $specTypes = \think\facade\Db::name('GoodsSpecType')
            ->where('goods_id', $goodsId)
            ->order('id', 'asc')
            ->select()
            ->toArray();

        // 构建 name => index 映射
        $dimIndexByName = [];
        $dimValuesByName = []; // name => [value1, value2, ...]
        foreach ($specTypes as $idx => $type) {
            $dimName = $type['name'] ?? '';
            if (!empty($dimName)) {
                $dimIndexByName[$dimName] = $idx;
                // 解析 value JSON 数组
                $values = json_decode($type['value'] ?? '[]', true);
                $dimValuesByName[$dimName] = [];
                foreach ($values as $v) {
                    if (isset($v['name'])) {
                        $dimValuesByName[$dimName][] = $v['name'];
                    }
                }
            }
        }

        // 3. 查询每个 spec_base_id 对应的 GoodsSpecValue
        $specBaseIds = array_column($specs, 'id');
        $specValues = \think\facade\Db::name('GoodsSpecValue')
            ->whereIn('goods_spec_base_id', $specBaseIds)
            ->select()
            ->toArray();

        // 4. 按 spec_base_id 分组，直接使用 GoodsSpecValue.name 字段确定维度名（更可靠）
        $specByBaseId = [];
        foreach ($specValues as $sv) {
            $baseId = $sv['goods_spec_base_id'];
            $value = $sv['value'] ?? '';

            // 通过值匹配找到对应的维度名（依赖 GoodsSpecType.value JSON 中的 name）
            $dimName = '';
            foreach ($dimValuesByName as $name => $values) {
                if (in_array($value, $values)) {
                    $dimName = $name;
                    break;
                }
            }

            if (!isset($specByBaseId[$baseId])) {
                $specByBaseId[$baseId] = [];
            }
            $specByBaseId[$baseId][] = [
                'type'  => $dimName,
                'value' => $value,
            ];
        }

        // 4. 解析座位模板中的 room 信息（用于提取 rowLabel, colNum 等）
        $rooms = $seatTemplate['seat_map']['rooms'] ?? [];
        $roomSeatInfo = []; // roomId => [rowLabel_colNum => ['rowLabel' => 'A', 'colNum' => 3, 'section' => [...]]]
        foreach ($rooms as $rIdx => $room) {
            $roomId = !empty($room['id']) ? $room['id'] : ('room_' . $rIdx);
            $sections = $room['sections'] ?? [];

            $map = $room['map'] ?? [];
            $seatsData = $room['seats'] ?? [];

            foreach ($map as $rowIndex => $rowStr) {
                $rowLabel = chr(65 + $rowIndex);
                $chars = mb_str_split($rowStr);

                foreach ($chars as $colIndex => $char) {
                    if ($char === '_' || $char === '-' || !isset($seatsData[$char])) {
                        continue;
                    }
                    $colNum = $colIndex + 1;

                    // 查找分区信息
                    $sectionInfo = null;
                    foreach ($sections as $sec) {
                        if (($sec['char'] ?? '') === $char) {
                            $sectionInfo = $sec;
                            break;
                        }
                    }

                    $roomSeatInfo[$roomId][$rowLabel . '_' . $colNum] = [
                        'rowLabel' => $rowLabel,
                        'colNum'   => $colNum,
                        'section'  => $sectionInfo,
                        'char'     => $char,
                    ];
                }
            }
        }

        // 5. 构建 seatSpecMap：seat_key → 完整规格
        foreach ($specs as $spec) {
            $extends = json_decode($spec['extends'] ?? '{}', true);
            $seatKey = $extends['seat_key'] ?? '';
            if (empty($seatKey)) continue;

            // 解析 seatKey 格式：roomId_rowLabel_colNum
            $parts = explode('_', $seatKey);
            if (count($parts) < 3) continue;
            $roomId = $parts[0];
            $rowLabel = $parts[1];
            $colNum = intval($parts[2]);

            // 提取各维度值
            $venueName = '';
            $sectionName = '';
            $seatName = '';
            $sessionName = '';
            $roomName = '';  // ← 演播室（第3维）
            foreach ($specByBaseId[$spec['id']] ?? [] as $specItem) {
                $specType = $specItem['type'] ?? '';
                $specVal = $specItem['value'] ?? '';
                switch ($specType) {
                    case '$vr-场次':
                        $sessionName = $specVal;
                        break;
                    case '$vr-场馆':
                        $venueName = $specVal;
                        break;
                    case '$vr-演播室':
                        $roomName = $specVal;
                        break;
                    case '$vr-分区':
                        $sectionName = $specVal;
                        break;
                    case '$vr-座位号':
                        $seatName = $specVal;
                        break;
                }
            }

            // 获取座位元信息
            $seatMeta = $roomSeatInfo[$roomId][$rowLabel . '_' . $colNum] ?? [
                'rowLabel' => $rowLabel,
                'colNum'   => $colNum,
                'section'  => null,
                'char'     => '',
            ];

            $seatSpecMap[$seatKey] = [
                'spec_base_id' => intval($spec['id']),
                'price'        => floatval($spec['price']),
                'inventory'     => intval($spec['inventory']),
                'spec'         => $specByBaseId[$spec['id']] ?? [],
                'rowLabel'     => $seatMeta['rowLabel'],
                'colNum'       => $seatMeta['colNum'],
                'roomId'       => $roomId,
                'roomName'     => $roomName,     // ← 演播室名（第3维）
                'section'      => $seatMeta['section'],
                'venueName'    => $venueName,
                'sectionName'  => $sectionName,
                'seatName'     => $seatName,
                'sessionName'  => $sessionName,
            ];
        }

        return $seatSpecMap;
    }
}
