<?php
namespace app\plugins\vr_ticket\service;

use think\facade\Db;

/**
 * VR票务 - 座位图服务（UniApp seatmap API 专用）
 *
 * 提供 seatSpecMap（含实时库存）+ goods_spec_data
 * 模板快照走 ShopXO Cache（TTL 60s），库存实时读 DB
 *
 * @package vr_ticket\service
 */
class SeatMapService
{
    /**
     * 缓存 key 前缀
     */
    const CACHE_KEY_PREFIX = 'vr_seatmap_';

    /**
     * 模板快照缓存 TTL（秒）
     */
    const CACHE_TTL = 60;

    /**
     * 获取座位图完整数据（含实时库存）
     *
     * @param int $goodsId
     * @return array [
     *   'seatSpecMap'     => [...],   // seatKey → {inventory, price, spec, ...}
     *   'goods_spec_data' => [...],  // 场次列表（含最低价）
     * ]
     */
    public static function GetSeatMap(int $goodsId): array
    {
        // 1. 读取 vr_goods_config（数组，取第一项）
        $vrConfigRaw = Db::name('Goods')
            ->where('id', $goodsId)
            ->value('vr_goods_config');

        $configs = json_decode($vrConfigRaw ?? '', true);
        if (empty($configs) || !is_array($configs)) {
            return ['seatSpecMap' => [], 'goods_spec_data' => []];
        }
        $config = $configs[0];

        $templateId = intval($config['template_id'] ?? 0);
        if ($templateId <= 0) {
            return ['seatSpecMap' => [], 'goods_spec_data' => []];
        }

        // 2. 获取座位模板（含 rooms[] / sections[] / map[]）
        $seatTemplate = self::getSeatTemplate($templateId);
        if (empty($seatTemplate)) {
            return ['seatSpecMap' => [], 'goods_spec_data' => []];
        }

        // 3. 构建 seatSpecMap（含 inventory，实时读 DB，包含已售）
        $seatSpecMap = self::buildSeatSpecMap($goodsId, $seatTemplate);

        // 4. 构建场次列表（从 sessions[] + seatSpecMap 合并最低价）
        $goodsSpecData = self::buildGoodsSpecData($config['sessions'] ?? [], $seatSpecMap);

        return [
            'seatSpecMap'      => $seatSpecMap,
            'goods_spec_data' => $goodsSpecData,
        ];
    }

    /**
     * 清除座位图缓存（订单支付成功后调用）
     *
     * @param int $goodsId
     * @return bool
     */
    public static function ClearCache(int $goodsId): bool
    {
        return \think\facade\Cache::delete(self::CACHE_KEY_PREFIX . $goodsId);
    }

    // ─────────────────────────────────────────────────────────
    // 私有方法
    // ─────────────────────────────────────────────────────────

    /**
     * 获取座位模板（走 ShopXO Cache，TTL 60s）
     *
     * @param int $templateId
     * @return array|null
     */
    private static function getSeatTemplate(int $templateId)
    {
        $cacheKey = self::CACHE_KEY_PREFIX . $templateId;
        $cached = \think\facade\Cache::get($cacheKey);
        if ($cached !== null) {
            return $cached;
        }

        $row = Db::name('vr_seat_templates')->find($templateId);
        if (empty($row)) {
            return null;
        }

        $seatMap = json_decode($row['seat_map'] ?? '{}', true);
        if (empty($seatMap)) {
            return null;
        }

        // 缓存（TTL = self::CACHE_TTL）
        \think\facade\Cache::set($cacheKey, $seatMap, self::CACHE_TTL);

        return $seatMap;
    }

    /**
     * 构建座位规格映射表（含 inventory，实时读 DB）
     *
     * 遍历所有 GoodsSpecBase（含 inventory=0 的已售座位），
     * 与 GoodsSpecType + GoodsSpecValue 关联，
     * 输出 seatSpecMap。
     *
     * @param int   $goodsId
     * @param array $seatTemplate seat_map JSON（已解析）
     * @return array seatSpecMap
     */
    private static function buildSeatSpecMap(int $goodsId, array $seatTemplate): array
    {
        $seatSpecMap = [];

        // 1. 查询当前商品所有 GoodsSpecBase（不过滤 inventory，获取所有座位含已售）
        $specs = Db::name('GoodsSpecBase')
            ->where('goods_id', $goodsId)
            ->select()
            ->toArray();

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

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

        $dimIndexByName = [];
        $dimValuesByName = []; // name → [value1, value2, ...]
        foreach ($specTypes as $idx => $type) {
            $dimName = $type['name'] ?? '';
            if (!empty($dimName)) {
                $dimIndexByName[$dimName] = $idx;
                $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 = Db::name('GoodsSpecValue')
            ->whereIn('goods_spec_base_id', $specBaseIds)
            ->select()
            ->toArray();

        // 4. 按 spec_base_id 分组，通过值匹配找到维度名
        $specByBaseId = [];
        foreach ($specValues as $sv) {
            $baseId = $sv['goods_spec_base_id'];
            $value = $sv['value'] ?? '';

            $dimName = '';
            foreach ($dimValuesByName as $name => $values) {
                if (in_array($value, $values)) {
                    $dimName = $name;
                    break;
                }
            }

            $specByBaseId[$baseId][] = [
                'type'  => $dimName,
                'value' => $value,
            ];
        }

        // 5. 解析座位模板中的 room 信息（用于提取 rowLabel, colNum, section 等）
        $rooms = $seatTemplate['rooms'] ?? [];
        $roomSeatInfo = []; // roomId → [rowLabel_colNum → [...]]
        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 = preg_split('//u', $rowStr, -1, PREG_SPLIT_NO_EMPTY);

                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,
                    ];
                }
            }
        }

        // 6. 构建 seatSpecMap：seatKey → 完整规格
        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 = '';
            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']), // ← 关键字段（0=已售）
                'spec'         => $specByBaseId[$spec['id']] ?? [],
                'rowLabel'     => $seatMeta['rowLabel'],
                'colNum'       => $seatMeta['colNum'],
                'roomId'       => $roomId,
                'roomName'     => $roomName,
                'section'      => $seatMeta['section'],
                'venueName'    => $venueName,
                'sectionName'  => $sectionName,
                'seatName'     => $seatName,
                'sessionName'  => $sessionName,
            ];
        }

        return $seatSpecMap;
    }

    /**
     * 构建 goods_spec_data（场次列表，含最低价）
     *
     * @param array $sessions    vr_goods_config.sessions[]
     * @param array $seatSpecMap
     * @return array
     */
    private static function buildGoodsSpecData(array $sessions, array $seatSpecMap): array
    {
        if (empty($sessions)) {
            return [];
        }

        $result = [];
        foreach ($sessions as $session) {
            $specName = ($session['start'] ?? '') . '-' . ($session['end'] ?? '');
            $minPrice = PHP_FLOAT_MAX;

            // 从 seatSpecMap 中找该场次的最低价
            foreach ($seatSpecMap as $info) {
                if (($info['sessionName'] ?? '') === $specName) {
                    $p = $info['price'] ?? PHP_FLOAT_MAX;
                    if ($p < $minPrice) {
                        $minPrice = $p;
                    }
                }
            }

            $result[] = [
                'spec_name' => $specName,
                'price'     => $minPrice < PHP_FLOAT_MAX ? $minPrice : 0,
                'start'     => $session['start'] ?? '',
                'end'       => $session['end'] ?? '',
            ];
        }

        return $result;
    }
}