<?php

declare(strict_types=1);

namespace App\Platform\Tmall\EntityParse;

use App\Constants\OrderStatus;
use App\Model\Company;
use App\Model\Model as Entity;
use App\Model\Product;
use App\Model\Store;
use App\Platform\AbstractOrderParse;
use App\Constants\PaymentMethod;
use App\Constants\OrderType;
use Carbon\Carbon;
use Hyperf\Collection\LazyCollection;
use InvalidArgumentException;

/**
 * 天猫订单解析器示例
 *
 * 展示如何继承 EntityParse 实现自定义解析逻辑
 */
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['store_id'])) {
            throw new InvalidArgumentException('store_id is required in metadata');
        }

        $store_id = $metadata['store_id'];

        $store = Store::find($store_id);

        if (!$store) {
            throw new InvalidArgumentException("Store with ID {$store_id} not found");
        }

        return $store;
    }

    /**
     * 实体数据映射
     *
     * 将原始数据映射为可供 Model 使用的数组集合
     *
     * @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) {

                $raw  = \json_encode($record);
                // 映射每条原始数据到 Model 可用的数组格式
                yield [
                    'company_id' => $this->getCompany()->id,
                    'platform_id' => $this->getPlatform()->id,
                    'store_id' => $this->getStore()->id,
                    'order_status_id' => $this->getOrderStatusId($record['status']),
                    'platform_order_id' => $record['tid'],
                    'payment_method_id' => $this->getPaymentMethodId(),
                    'presale' => false,
                    'total_amount' => $record['total_fee'],
                    'total_paid' => $record['payment'],
                    'total_discount' => $record['discount_fee'],
                    // 实际收到的金额，如果平台有商家补贴，此金额需要重新计算 - 部分退款订单也影响此字段的值
                    'total_received' => $record['received_payment'],
                    'freight_fee' => 0,
                    'tax_fee' => 0,
                    'discount_fee' => 0,
                    'commission_fee' => 0,
                    'coupon_amount' => 0,
                    'voucher_amount' => 0,
                    'order_type_id' => OrderType::Normor_Order->value,
                    'created_date' => Carbon::parse($record['created'], $this->getStore()->getTimezoneString())->format('Y-m-d H:i:sP'),
                    'updated_date' => isset($record['modified']) ? Carbon::parse($record['modified'], $this->getStore()->getTimezoneString())->format('Y-m-d H:i:sP') : null,
                    'paid_date' => isset($record['pay_time']) ? Carbon::parse($record['pay_time'], $this->getStore()->getTimezoneString())->format('Y-m-d H:i:sP') : null,
                    'shipping_date' => isset($record['consign_time']) ? Carbon::parse($record['consign_time'], $this->getStore()->getTimezoneString())->format('Y-m-d H:i:sP') : null,
                    'zipcode' => $record['receiver_zip'] ?? '',
                    'city' => $record['receiver_city'] ?? '',
                    'province' => $record['receiver_state'] ?? '',
                    'country' => 'CN',
                    'raw' => $raw,
                    'ext' => null,
                    'buyer_user_id' => $record['buyer_open_uid'],
                    'hash' => \md5($raw),
                    'created_at' => Carbon::now()->format('Y-m-d H:i:sP'),
                    'updated_at' => Carbon::now()->format('Y-m-d H:i:sP'),
                ];

            }
        });
    }

    /**
     * 获取实体的唯一键字段（用于 upsert 的 uniqueBy 参数）
     *
     * 定义订单的唯一约束字段组合
     *
     * @return array 唯一键字段名数组
     */
    public function getUniqueBy(): array
    {
        // 天猫订单的唯一性由店铺 + 平台订单号确定(实际上由平台订单号就已经足够)
        // @attention create_date 为数据库强制要求，必需携带
        return ['store_id', 'platform_order_id', 'created_date'];
    }

    /**
     * 获取可更新的字段列表（用于 upsert 的 update 参数）
     *
     * 明确定义哪些字段在更新时可以被修改
     * 排除：主键、唯一键、创建时间、关联 ID 等不应变更的字段
     *
     * @return array 可更新字段名数组
     */
    public function getUpdateFields(): array
    {
        // 方案1：手动指定可更新字段（推荐，最明确）
        // 根据实际业务需求添加其他可更新字段
        return [
            'company_id',
            'platform_id',
            'store_id',
            'order_status_id',
            'platform_order_id',
            'payment_method_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',
            'created_date',
            'updated_date',
            'paid_date',
            'shipping_date',
            'zipcode',
            'city',
            'province',
            'country',
            'raw',
            'ext',
            'buyer_user_id',
            'hash',
            'updated_at',  // 更新时刷新，created_at 不包含以保留原始创建时间
        ];

        // 方案2：动态计算（如果字段较多且经常变动）
        // $entity = $this->entityMatch($this->getData());
        // $excludeFields = array_merge(
        //     ['id', 'created_at', 'created_date', 'company_id', 'platform_id'],
        //     $this->getUniqueBy()
        // );
        // return $this->getTableColumnsExcept($entity, $excludeFields);
    }



    /**
     * 根据淘宝订单状态确定对应的 Tools 订单状态
     *
     * @param string $platform_order_status 淘宝平台订单状态
     * @return int Tools 订单状态 ID
     */
    public function getOrderStatusId(string $platform_order_status): int
    {
        $status_map = $this->orderStatusMap();

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

    /**
     * 淘宝订单状态到 Tools 订单状态的映射
     *
     * @return array<string, int>
     */
    private function orderStatusMap(): array
    {
        return [
            // Payment pending (1)
            'TRADE_NO_CREATE_PAY'    => OrderStatus::PAYMENT_PENDING->value,     // 没有创建支付宝交易
            'WAIT_BUYER_PAY'         => OrderStatus::PAYMENT_PENDING->value,     // 等待买家付款
            'PAY_PENDING'            => OrderStatus::PAYMENT_PENDING->value,     // 国际信用卡支付付款确认中
            'WAIT_PRE_AUTH_CONFIRM'  => OrderStatus::PAYMENT_PENDING->value,     // 0元购合约中

            // Payment fail (2)
            'TRADE_CLOSED_BY_TAOBAO' => OrderStatus::PAYMENT_FAIL->value,        // 付款以前，卖家或买家主动关闭交易

            // Payment complete (3)
            'SELLER_CONSIGNED_PART'  => OrderStatus::PAYMENT_COMPLETE->value,    // 卖家部分发货
            'WAIT_SELLER_SEND_GOODS' => OrderStatus::PAYMENT_COMPLETE->value,    // 等待卖家发货,即:买家已付款

            // Awaiting shipment (4)
            'PAID_FORBID_CONSIGN'    => OrderStatus::AWAITING_SHIPMENT->value,   // 拼团中订单或者发货强管控的订单，已付款但禁止发货

            // Shipped (5)
            'WAIT_BUYER_CONFIRM_GOODS' => OrderStatus::SHIPPED->value,           // 等待买家确认收货,即:卖家已发货
            'TRADE_BUYER_SIGNED'       => OrderStatus::SHIPPED->value,           // 买家已签收,货到付款专用

            // Finished (8)
            'TRADE_FINISHED'         => OrderStatus::FINISHED->value,            // 交易成功

            // Cancel before shipping (9)
            'TRADE_CLOSED'           => OrderStatus::CANCEL_BEFORE_SHIPPING->value, // 付款以后用户退款成功，交易自动关闭
        ];
    }


    public function getPaymentMethodId() : int
    {
        // @attention   暂时固定返回支付方式为支付宝， 其他平台需要定义付款方式映射
        return PaymentMethod::ALIPAY_CN->value;
    }


    /**
     *
     * orderItems 的输出结果为 \App\Model\OrderItem::fill() 可以直接使用的数据格式
     *
     * @param array $raw_data
     * @param array $platform_orders_id_to_local_db_order_id_map

     * @return array
     */
    public function formatOrderItemsFromRaw(array $raw_data, array $platform_orders_id_to_local_db_order_id_map): array
    {
        // 由于 $raw_data 是批量数据，包含多条订单结果，因此订单子项需要从集合中提取
        // Tmall 平台响应体的数据格式为： collection->payload->orders
        // $platform_orders_id_to_local_db_order_id_map 内部元素数据格式为 [platform_order_id =>  local db order id]

        $items = [];
        $product_keys = []; // 索引 => 查询键

        foreach ($raw_data as $raw_orders) {
            $parent_order_created_date = Carbon::parse($raw_orders['created']);

            foreach ($raw_orders['orders']['order'] as $raw_order_item) {
                // 数据库中父订单 id
                $db_order_id = $platform_orders_id_to_local_db_order_id_map[$raw_orders['tid']];
                $platform_order_id = strval($raw_orders['tid']);

                // 记录当前索引
                $index = count($items);

                // 先添加 item，product_id 初始为 0
                $items[] = $this->tmallOrderItemMap($raw_order_item, $platform_order_id, $db_order_id, $parent_order_created_date, 0);

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

        // 批量查询产品 并使用匹配到的产品 覆写 $items product_id 字段的值
        if (!empty($product_keys)) {
            $products_id_map = $this->batchQueryProducts($product_keys);
            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 平台 SKU 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 索引 => 查询键 的映射
     * @return array 查询键 => 产品 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;
    }

    /**
     * Tmall 订单子项映射转换
     * @return void 
     */
    private function tmallOrderItemMap(array $item, string $platform_order_id, int $parent_order_id, Carbon $parent_order_created_date): array
    {

        // $item = [
        //     "adjust_fee" => "0.00",
        //     "buyer_rate" => false,
        //     "cid" => 50026872,
        //     "consign_due_time" => "2_5",
        //     "discount_fee" => "231.98",
        //     "divide_order_fee" => "504.00",
        //     "is_bybt_order" => false,
        //     "is_daixiao" => false,
        //     "is_idle" => "0",
        //     "is_jzfx" => false,
        //     "is_oversold" => false,
        //     "nr_outer_iid" => "768990037900",
        //     "num" => 1,
        //     "num_iid" => 637901668632,
        //     "oid" => 4932549972242808538,
        //     "oid_str" => "4932549972242808538",
        //     "order_attr" => "{"esDate":"2025-12-14","pushTime":"2025-12-09 11:30:00"}",
        //     "order_from" => "WAP,WAP",
        //     "outer_iid" => "768990037900",
        //     "outer_sku_id" => "768990037900",
        //     "part_mjz_discount" => "15.00",
        //     "payment" => "504.00",
        //     "pic_path" => "https://img.alicdn.com/bao/uploaded/i4/2413132940/O1CN01duCukP1XaZLX2jVQy_!!2413132940.jpg",
        //     "price" => "693.00",
        //     "refund_status" => "NO_REFUND",
        //     "s_tariff_fee" => "0.00",
        //     "seller_rate" => false,
        //     "seller_type" => "B",
        //     "sku_id" => "6123547511321",
        //     "sku_properties_name" => "颜色分类:高倍Omega鱼油软胶囊 180粒/瓶",
        //     "snapshot_url" => "za:4932549972242808538_1",
        //     "status" => "WAIT_SELLER_SEND_GOODS",
        //     "store_code" => "STORE_11388627",
        //     "sub_order_tax_fee" => "57.98",
        //     "sub_order_tax_promotion_fee" => "0.00",
        //     "sub_order_tax_rate" => "0",
        //     "tax_coupon_discount" => "57.98",
        //     "tax_free" => true,
        //     "title" => "【优惠价】NordicNaturals挪威小鱼dha深海鱼油Omega3成人rTG高纯度epa胶囊",
        //     "total_fee" => "461.02",
        // ]


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