<?php

declare(strict_types=1);

namespace App\Platform\Shopee\EntityParse;

use App\Model\Company;
use App\Model\Model as Entity;
use App\Model\Product;
use App\Model\Store;
use App\Platform\AbstractOrderParse;
use App\Platform\Shopee\Constants\OrderStatus;
use App\Constants\PaymentMethod;
use Carbon\Carbon;
use Hyperf\Collection\LazyCollection;
use Hyperf\Context\ApplicationContext;
use Psr\Log\LoggerInterface;
use InvalidArgumentException;

/**
 * Shopee 订单解析器
 *
 * 继承 AbstractOrderParse，实现 Shopee 平台特定的订单解析逻辑
 * 通过 AbstractOrderParse 自动满足 OrderContract 契约
 */
class Order extends AbstractOrderParse
{
    /**
     * 公司作用域匹配
     *
     * 从 metadata 中提取 company_id，然后查询数据库获取公司对象
     *
     * @param array $metadata
     * @return Company
     * @throws InvalidArgumentException
     */
    public function companyScopeMatch(array $metadata): Company
    {
        // 验证必需字段
        if (!isset($metadata['company_id'])) {
            throw new InvalidArgumentException('company_id is required in metadata');
        }

        $company_id = $metadata['company_id'];

        $company = Company::find($company_id);

        if (!$company) {
            throw new InvalidArgumentException("Company with ID {$company_id} not found");
        }

        return $company;
    }

    /**
     * 店铺作用域匹配
     *
     * 从 metadata 中提取 store_id，然后查询数据库获取店铺对象
     *
     * @param array $metadata
     * @return Store
     * @throws InvalidArgumentException
     */
    public function storeScopeMatch(array $metadata): Store
    {
        // 验证必需字段
        if (!isset($metadata['platform_store_id'])) {
            throw new InvalidArgumentException('platform_store_id is required in metadata');
        }

        $platform_store_id = $metadata['platform_store_id'];

        $shopee_platform_id = 25;

        $store = Store::where('platform_id','=', $shopee_platform_id)
            ->where('platform_store_id', '=', $platform_store_id)
            ->first();

        if (!$store) {
            throw new InvalidArgumentException("Platform shopee store id {$shopee_platform_id} not found");
        }

        return $store;
    }

    /**
     * 实体数据映射
     *
     * 将原始数据映射为可供 Model 使用的数组集合
     *
     * @attention 当前返回格式为 ['order' => [...], 'items' => [...]]
     *            但 OrderConsumer 第 153-157 行期望直接返回订单数据数组（参考 Tmall 实现）
     *            需要调整返回格式以兼容 OrderConsumer 的 upsert 操作
     *
     * @TODO 调整返回格式：
     *       - 方案1：改为直接返回订单数据数组（与 Tmall 一致）
     *       - 方案2：修改 OrderConsumer 以支持当前的嵌套结构
     *
     * @param array $raw_data 原始数据数组，通常来自 $data['raw_data']
     * @return LazyCollection 返回 LazyCollection，每个元素为可供 Model::fill() 使用的数组
     */
    public function entityMap(array $raw_data): LazyCollection
    {
        // 使用 LazyCollection 进行延迟处理，提高性能
        return LazyCollection::make(function () use ($raw_data) {
            // 如果 raw_data 是单个记录，转换为数组
            $records = isset($raw_data[0]) ? $raw_data : [$raw_data];

            foreach ($records as $record) {

                dump($record);

                // 根据实际业务需求映射其他字段
                // 映射每条原始数据到 Order Model 可用的数组格式
                // @attention 此处业务决定了 电商平台数据 和 数据仓库 之间的映射关系

                // 返回包含订单数据和子项数据的结构
                $raw  = \json_encode($record);

                yield [
                    'company_id' => $this->getCompany()->id,
                    'platform_id' => $this->platform->id,
                    'store_id' => $this->getStore()->id,
                    'order_status_id'=> OrderStatus::{$record['order_status']}->value,
                    'platform_order_id' => $record['order_sn'],
                    'payment_method_id' => $this->getPaymentMethodId(),
                    'buyer_user_id' => $record['buyer_user_id'] ?? null,
                    'presale' => false, // shopee 平台暂不存类型为 presales 的订单
                    'total_amount' => $record['total_amount'] ?? 0,
                    // @link https://open.shopee.com/documents/v2/v2.order.get_order_detail?module=94&type=1
                    // shopee 定义 $record['total_amount'] 为买家付款金额字段
                    // The total amount paid by the buyer for the order. This amount includes the total sale price of items,
                    // shipping cost beared by buyer; and offset by Shopee promotions if applicable. This value
                    // will only return after the buyer has completed payment for the order.
                    'total_paid' => $record['total_amount'] ?? 0,
                    'total_discount' => 0,
                    'total_received' => 0,
                    // @link https://open.shopee.com/documents/v2/v2.order.get_order_detail?module=94&type=1
                    // $record['actual_shipping_fee'] - The actual shipping fee of the order if available from external logistics partners.
                    'freight_fee' => $record['actual_shipping_fee'] ?? 0,
                    'tax_fee' => 0,
                    'discount_fee' => 0,
                    'commission_fee' => 0,
                    'coupon_amount' => 0,
                    'voucher_amount' => 0,
                    'order_type_id' => 0,
                    'created_date' => Carbon::createFromTimestamp($record['create_time'], $this->getStore()->getTimezoneString()), // 订单的创建时间
                    'updated_date' => Carbon::createFromTimestamp($record['update_time'], $this->getStore()->getTimezoneString()), // 最近的一次订单更新时间
                    'paid_date' => $record['pay_time'] ? Carbon::createFromTimestamp($record['pay_time'], $this->getStore()->getTimezoneString()) : null,
                    'shipping_date' => $record['pickup_done_time'] > 0 ? Carbon::createFromTimestamp($record['pickup_done_time'], $this->getStore()->getTimezoneString()) : null,
                    'country' => $record['region'], // address 等地理位置信息因 shopee 数据保护协议已被隐藏, 目前仅提供 ISO 格式国家代码
                    'raw' => $raw,
                    'ext' => null,
                    'hash' => \md5($raw),
                    'created_at' => date('Y-m-d H:i:s'),
                    'updated_at' => date('Y-m-d H:i:s')
                ];
            }
        });
    }

    /**
     * 获取唯一键字段（对应数据库唯一索引）
     *
     * 对应数据库约束：
     * UNIQUE INDEX orders_store_platform_order_unique (store_id, platform_order_id)
     *
     * @return array
     */
    public function getUniqueBy(): array
    {
        // @attention create_date 为数据库强制要求，必需携带
        return ['store_id', 'platform_order_id', 'created_date'];
    }

    /**
     * 获取可更新字段列表
     *
     * 排除：主键、唯一键、创建时间、关联 ID
     *
     * @return array
     */
    public function getUpdateFields(): array
    {
        // 手动指定（推荐：明确且高效，无数据库查询开销）
        return [
            'order_status_id',
            'payment_method_id',
            'buyer_user_id',
            'presale',
            'total_amount',
            'total_paid',
            'total_discount',
            'total_received',
            'freight_fee',
            'tax_fee',
            'discount_fee',
            'commission_fee',
            'coupon_amount',
            'voucher_amount',
            'order_type_id',
            'updated_date',
            'paid_date',
            'shipping_date',
            'zipcode',
            'city',
            'province',
            'country',
            'raw',
            'ext',
            'hash',
            'updated_at',  // 更新时刷新，created_at 不包含以保留原始创建时间
        ];

        // 动态计算方案（如果表字段经常变化，可以使用）：
        // $entity = $this->entityMatch([
        //     'company_id' => $this->getCompany()->id,
        //     'platform_id' => $this->getPlatform()->id,
        //     'store_id' => $this->getStore()->id,
        // ]);
        // $excludeFields = array_merge(
        //     ['id', 'created_at', 'created_date', 'company_id', 'platform_id'],
        //     $this->getUniqueBy()
        // );
        // return $this->getTableColumnsExcept($entity, $excludeFields);
    }

    /**
     * 根据 Shopee 订单状态确定对应的本地订单状态
     *
     * @required OrderConsumer 要求实现此方法（第 130-132 行）
     * @see \App\Constants\OrderStatus
     *
     * @param string $platform_order_status Shopee 平台订单状态
     * @return int 本地订单状态 ID
     */
    public function getOrderStatusId(string $platform_order_status): int
    {
        $status_map = $this->orderStatusMap();

        return $status_map[$platform_order_status] ?? \App\Constants\OrderStatus::PAYMENT_COMPLETE->value;
    }

    /**
     * Shopee 订单状态到本地订单状态的映射表
     *
     * @see \App\Platform\Shopee\Constants\OrderStatus Shopee 平台订单状态枚举
     * @see \App\Constants\OrderStatus 本地订单状态枚举
     *
     * @return array<string, int>
     */
    private function orderStatusMap(): array
    {
        return [
            // 未付款 -> 等待付款
            'UNPAID' => \App\Constants\OrderStatus::PAYMENT_PENDING->value,

            // 可发货（已付款，等待卖家安排发货）-> 付款完成
            'READY_TO_SHIP' => \App\Constants\OrderStatus::PAYMENT_COMPLETE->value,

            // 已处理（卖家已安排发货并获取物流单号）-> 等待发货
            'PROCESSED' => \App\Constants\OrderStatus::AWAITING_SHIPMENT->value,

            // 重新发货（3PL 取件失败，需要重新安排发货）-> 等待发货
            'RETRY_SHIP' => \App\Constants\OrderStatus::AWAITING_SHIPMENT->value,

            // 已发货（包裹已交给 3PL 或已被 3PL 取走）-> 已发货
            'SHIPPED' => \App\Constants\OrderStatus::SHIPPED->value,

            // 待确认收货（买家已收到订单）-> 已发货
            'TO_CONFIRM_RECEIVE' => \App\Constants\OrderStatus::SHIPPED->value,

            // 取消中（订单取消正在处理）-> 取消请求中
            'IN_CANCEL' => \App\Constants\OrderStatus::CANCEL_REQUESTED->value,

            // 已取消 -> 取消确认
            'CANCELLED' => \App\Constants\OrderStatus::CANCEL_CONFIRMED->value,

            // 退货中（买家请求退货，退货正在处理）-> 取消请求中
            'TO_RETURN' => \App\Constants\OrderStatus::CANCEL_REQUESTED->value,

            // 已完成 -> 完成
            'COMPLETED' => \App\Constants\OrderStatus::FINISHED->value,
        ];
    }

    /**
     * 获取支付方式 ID
     *
     * @required OrderConsumer 要求实现此方法（第 136-138 行）
     * @see \App\Constants\PaymentMethod
     * 
     *      // 支付方式映射表：Shopee 字符串 => PaymentMethod 枚举
     * 因为 shopee 官方文档 https://open.shopee.cn/developer-guide/31 “V2.0 Data Definition” 
     * 和接口数据返回的结果对不上，因此统一设置为在线支付
     *  
     *
     * @return int 支付方式 ID
     */
    public function getPaymentMethodId(): int
    {
        // 实现 Shopee 支付方式到本地 PaymentMethod 枚举的映射
        return PaymentMethod::ONLINE_PAYMENT->value;
    }

    /**
     * 从原始数据格式化订单子项
     *
     * @required OrderConsumer 要求实现此方法（第 124-126 行，第 177 行调用）
     *
     * @param array $raw_data 原始数据数组
     * @param array $platform_orders_id_to_local_db_order_id_map 平台订单 ID 到本地数据库订单 ID 的映射 [platform_order_id => local_db_order_id]
     *
     * 
     * @return array 格式化后的订单子项数据，可供 OrderItem::fill() 使用]
     * 
     */
    public function formatOrderItemsFromRaw(array $raw_data, array $platform_orders_id_to_local_db_order_id_map): array
    {
        $items = [];
        $product_keys = []; // 索引 => 查询键

        foreach ($raw_data as $raw_orders) {
            $parent_order_created_date = Carbon::createFromTimestamp($raw_orders['create_time'], $this->getStore()->getTimezoneString());
            foreach ($raw_orders['item_list'] as $raw_order_item) {
                $db_order_id = $platform_orders_id_to_local_db_order_id_map[$raw_orders['order_sn']];

                $index = count($items);
                $items[] = $this->orderItemMap($raw_order_item, $raw_orders['order_sn'], $db_order_id, $parent_order_created_date);

                // 记录索引对应的产品查询键
                $model_id = !empty($raw_order_item['model_id']) ? (string)$raw_order_item['model_id'] : null;
                $product_keys[$index] = $this->buildProductMapKey((string)$raw_order_item['item_id'], $model_id);
            }
        }

        // 批量查询产品 并使用匹配到的产品 覆写 $items product_id 字段的值
        if (!empty($product_keys)) {
            $products_id_map = $this->batchQueryProducts($product_keys);

            // 直接用索引更新 product_id
            foreach ($product_keys as $index => $key) {
                if (isset($products_id_map[$key])) {
                    $items[$index]['product_id'] = $products_id_map[$key];
                }
            }
        }

        return $items;
    }

    /**
     * 构建产品映射键
     *
     * @param string $item_id 平台商品 ID
     * @param string|null $model_id 平台规格 ID
     * @return string
     */
    private function buildProductMapKey(string $item_id, ?string $model_id): string
    {
        return $item_id . ':' . ($model_id ?? 'null');
    }

    /**
     * 批量查询产品ID
     *
     * 使用 PostgreSQL VALUES + JOIN 语法优化，避免生成冗长的 OR 条件链
     *
     * @param array $product_keys 索引 => "item_id:model_id" 格式的键
     * @return array "item_id:model_id" => product_id 的映射
     */
    private function batchQueryProducts(array $product_keys): array
    {
        $store_id = $this->getStore()->id;
        $unique_keys = array_unique(array_values($product_keys));

        if (empty($unique_keys)) {
            return [];
        }

        // 构建 VALUES 子句和绑定参数
        $values = [];
        $bindings = [];

        foreach ($unique_keys as $key) {
            [$item_id, $model_id] = explode(':', $key, 2);
            $values[] = '(?::text, ?::text)';
            $bindings[] = $item_id;
            $bindings[] = $model_id === 'null' ? null : $model_id;
        }

        $valuesClause = implode(', ', $values);
        $bindings[] = $store_id;

        // PostgreSQL 原生 SQL：VALUES 作为驱动表（小表在左侧）
        // store_id 条件移入 JOIN ON 子句，让索引过滤更早介入
        $sql = "
            SELECT p.id, p.platform_item_id, p.platform_model_id
            FROM (VALUES {$valuesClause}) AS v(item_id, model_id)
            INNER JOIN products p
            ON p.store_id = ?
               AND p.platform_item_id = v.item_id
               AND (p.platform_model_id = v.model_id OR (v.model_id IS NULL AND p.platform_model_id IS NULL))
        ";

        $products = \Hyperf\DbConnection\Db::select($sql, $bindings);

        // 构建映射
        $map = [];
        foreach ($products as $product) {
            $key = $this->buildProductMapKey($product->platform_item_id, $product->platform_model_id);
            $map[$key] = $product->id;
        }

        return $map;
    }

    /**
     * Shopee 订单子项映射转换
     *
     * @param array $item 单个订单子项原始数据
     * @param string $platformOrderId 平台订单 ID
     * @param int $parentOrderId 本地数据库父订单 ID
     * @param string $parentOrderCreatedDate 父订单创建时间
     * @return array 映射后的订单子项数据
     */
    private function orderItemMap(array $item,  string $platform_order_id, int $parent_order_id, Carbon $parent_order_created_date): array
    {
        // @TODO 实现 Shopee 订单子项字段映射
        // 参考现有的 parseOrderItems() 方法中的映射逻辑
        // 需要额外添加 order_id 和 created_date 字段

        // @doc 见 https://open.shopee.com/documents/v2/v2.order.get_order_detail?module=94&type=1 文档

        // The after-discount price of the item in the listing currency. 
        // If there is no discount, this value will be same as that of model_original_price. 
        // In case of bundle deal item, this value will return 0 as by design bundle deal discount will not be breakdown to item/model level. Due to technical restriction, the value will return the price before bundle deal if we don't configure it to 0. Please call GetEscrowDetails if you want to calculate item-level discounted price for bundle deal item.

        return [
            'company_id' => $this->getCompany()->id,
            'platform_id' => $this->getPlatform()->id,
            'store_id' => $this->getStore()->id,
            'order_id' => $parent_order_id,
            'platform_order_id' => $platform_order_id,
            'sub_order_id' => $item['order_item_id'],
            // @attention  sku 的处理需要仅以规范和约束，确保 sku 准确
            'sub_order_type_id' => null,
            'product_id' => 0, // 值为 0 表示未找到产品 id， 之后会被批量查询覆盖
            'platform_product_id' =>$item['item_id'],
            // @attention @TODO 需要对 运营侧的产品维护做进一步规范
            'product_sku' => $item['model_sku'] ?? $item['item_sku'] ?? null,
            // @attention @TODO 需要对 运营侧的产品维护做进一步规范
            'product_barcode' => null,
            'unit_price' => (float)($item['model_discounted_price'] ?? $item['model_original_price'] ?? 0),
            'quantity' =>  (int)($item['model_quantity_purchased'] ?? 1),
            'discount' => ((float)($item['model_original_price'] ?? 0) - (float)($item['model_discounted_price'] ?? $item['model_original_price'] ?? 0)) * (int)($item['model_quantity_purchased'] ?? 1),
            'total' => (float)($item['model_discounted_price'] ?? $item['model_original_price'] ?? 0) * (int)($item['model_quantity_purchased'] ?? 1),
            // @attention 扩展字段，用来存储其他信息
            'ext' => null,
            'created_date' => $parent_order_created_date,
        ];
    }
}
