<?php

declare(strict_types=1);

namespace App\Platform\Shopee\EntityParse;

use App\Constants\RefundStatus;
use App\Constants\RefundType;
use App\Platform\Shopee\Constants\ReturnStatus as ShopeeReturnStatus;
use App\Model\Company;
use App\Model\Order;
use App\Model\Store;
use App\Platform\AbstractRefundParse;
use Carbon\Carbon;
use Hyperf\Collection\LazyCollection;
use InvalidArgumentException;

/**
 * Shopee 退款解析器
 *
 * Shopee 具有完整的父子退款结构：一个 return 包含多个 item。
 * 每个 return 同时写入 refunds（主记录）和 refund_items（明细）两张表。
 */
class Refund extends AbstractRefundParse
{
    /**
     * 缓存 entityMap 中查询到的订单日期映射，供 formatRefundItemsFromRaw 复用
     * [store_id:platform_order_id => ['order_created_date' => ..., 'order_paid_date' => ...]]
     */
    protected array $orderDatesMap = [];

    /**
     * 公司作用域匹配
     *
     * @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;
    }

    /**
     * 店铺作用域匹配
     *
     * Shopee 使用 platform_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 {$platform_store_id} not found");
        }

        return $store;
    }

    /**
     * 实体数据映射 - 映射到 refunds 表
     *
     * @param array $raw_data 原始数据数组
     * @return LazyCollection 每个元素为可供 Refund Model::fill() 使用的数组
     */
    public function entityMap(array $raw_data): LazyCollection
    {
        $records = isset($raw_data[0]) ? $raw_data : [$raw_data];
        $tz = $this->getStore()->getTimezoneString();
        $mapped = [];

        foreach ($records as $record) {
            $raw = \json_encode($record);
            $refund_amount = (float) ($record['refund_amount'] ?? 0);

            $mapped[] = [
                'company_id' => $this->getCompany()->id,
                'platform_id' => $this->getPlatform()->id,
                'store_id' => $this->getStore()->id,
                'order_id' => $record['t_order_id'] ?? null,
                'platform_order_id' => $record['order_sn'],
                'platform_refund_id' => $record['return_sn'],
                'refund_status_id' => $this->getRefundStatusId($record['status']),
                'refund_type_id' => $this->getRefundTypeId($record),
                'reason' => $record['text_reason'] ?? $record['reason'] ?? null,
                'refund_amount' => $refund_amount,
                'freight_refund' => 0,
                'refund_total' => $refund_amount,
                'currency' => $record['currency'] ?? 'USD',
                'buyer_user_id' => $record['user']['username'] ?? null,
                'order_created_date' => null,
                'order_paid_date' => null,
                'created_date' => Carbon::createFromTimestamp($record['create_time'], $tz)->format('Y-m-d H:i:sP'),
                'updated_date' => isset($record['update_time']) ? Carbon::createFromTimestamp($record['update_time'], $tz)->format('Y-m-d H:i:sP') : null,
                'completed_date' => ($record['status'] === 'CLOSED' || $record['status'] === 'ACCEPTED') && isset($record['update_time'])
                    ? Carbon::createFromTimestamp($record['update_time'], $tz)->format('Y-m-d H:i:sP')
                    : null,
                'raw' => $raw,
                'ext' => null,
                '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'),
            ];
        }

        $mapped = $this->fillOrderDates($mapped);

        return LazyCollection::make($mapped);
    }

    /**
     * 获取实体的唯一键字段
     *
     * @return array
     */
    public function getUniqueBy(): array
    {
        return ['store_id', 'platform_refund_id'];
    }

    /**
     * 获取可更新的字段列表
     *
     * @return array
     */
    public function getUpdateFields(): array
    {
        return [
            'order_id',
            'refund_status_id',
            'refund_type_id',
            'reason',
            'refund_amount',
            'freight_refund',
            'refund_total',
            'buyer_user_id',
            'order_created_date',
            'order_paid_date',
            'updated_date',
            'completed_date',
            'raw',
            'ext',
            'hash',
            'updated_at',
        ];
    }

    /**
     * 格式化退款子项数据 - 映射到 refund_items 表
     *
     * Shopee 一个 return 包含多个 item，每个 item 映射为一条 refund_item
     *
     * @param array $raw_data 原始数据数组
     * @param array $platform_refund_id_to_local_refund_id_map [platform_refund_id => local db refund id]
     * @return array
     */
    public function formatRefundItemsFromRaw(array $raw_data, ?array $platform_refund_id_to_local_refund_id_map): array
    {
        $records = isset($raw_data[0]) ? $raw_data : [$raw_data];
        $items = [];
        $tz = $this->getStore()->getTimezoneString();

        foreach ($records as $record) {
            $return_sn = $record['return_sn'];
            $refund_id = $platform_refund_id_to_local_refund_id_map[$return_sn] ?? 0;
            $refund_status_id = $this->getRefundStatusId($record['status']);
            $refund_type_id = $this->getRefundTypeId($record);

            foreach ($record['item'] ?? [] as $item) {
                $raw = \json_encode($item);

                $items[] = [
                    'company_id' => $this->getCompany()->id,
                    'platform_id' => $this->getPlatform()->id,
                    'store_id' => $this->getStore()->id,
                    'refund_id' => $refund_id,
                    'platform_parent_refund_id' => $return_sn,
                    'platform_refund_id' => strval($item['item_id']) . '_' . strval($item['model_id'] ?? 0),
                    'refund_status_id' => $refund_status_id,
                    'refund_type_id' => $refund_type_id,
                    'reason' => $record['text_reason'] ?? $record['reason'] ?? null,
                    'currency' => $record['currency'] ?? 'USD',
                    'buyer_user_id' => $record['user']['username'] ?? null,
                    'platform_order_id' => $record['order_sn'],
                    'platform_sub_order_id' => null,
                    'platform_product_id' => strval($item['item_id']),
                    'quantity' => $item['amount'] ?? 0,
                    'refund_amount' => (float) ($item['refund_amount'] ?? 0),
                    'order_created_date' => $this->orderDatesMap[$this->getStore()->id . ':' . $record['order_sn']]['order_created_date'] ?? null,
                    'order_paid_date' => $this->orderDatesMap[$this->getStore()->id . ':' . $record['order_sn']]['order_paid_date'] ?? null,
                    'created_date' => Carbon::createFromTimestamp($record['create_time'], $tz)->format('Y-m-d H:i:sP'),
                    'updated_date' => isset($record['update_time']) ? Carbon::createFromTimestamp($record['update_time'], $tz)->format('Y-m-d H:i:sP') : null,
                    'completed_date' => ($record['status'] === 'CLOSED' || $record['status'] === 'ACCEPTED') && isset($record['update_time'])
                        ? Carbon::createFromTimestamp($record['update_time'], $tz)->format('Y-m-d H:i:sP')
                        : null,
                    'raw' => $raw,
                    'ext' => null,
                    'created_at' => Carbon::now()->format('Y-m-d H:i:sP'),
                    'updated_at' => Carbon::now()->format('Y-m-d H:i:sP'),
                ];
            }
        }

        return $items;
    }

    /**
     * 根据退款子项的 store_id + platform_order_id 查询订单，
     * 将 order_created_date 和 order_paid_date 填入 $items 数组
     *
     * @param array $items 数据数组（refunds 或 refund_items）
     * @return array 填充了订单日期的数组
     */
    protected function fillOrderDates(array $items): array
    {
        // 收集尚未缓存的 lookup 条件
        $lookups = [];
        foreach ($items as $item) {
            $key = $item['store_id'] . ':' . $item['platform_order_id'];
            if (!isset($this->orderDatesMap[$key]) && !isset($lookups[$key])) {
                $lookups[$key] = [
                    'store_id' => $item['store_id'],
                    'platform_order_id' => $item['platform_order_id'],
                    'created_date' => $item['created_date'],
                ];
            }
        }

        // 仅查询未缓存的部分
        if (!empty($lookups)) {
            $newDates = $this->queryOrderDates($lookups);
            $this->orderDatesMap = array_merge($this->orderDatesMap, $newDates);
            dump("Matched " . count($newDates) . " orders for " . count($lookups) . " refund item lookups");
        }

        foreach ($items as &$item) {
            $key = $item['store_id'] . ':' . $item['platform_order_id'];
            if (isset($this->orderDatesMap[$key])) {
                $item['order_created_date'] = $this->orderDatesMap[$key]['order_created_date'];
                $item['order_paid_date'] = $this->orderDatesMap[$key]['order_paid_date'];
            }
        }
        unset($item);

        return $items;
    }

    /**
     * 根据 store_id + platform_order_id 批量查询订单的创建时间和付款时间
     *
     * shopee 平台订单周期长，搜索周期改为 4 个月
     * 订单搜索范围：[退款 created_date - 4个月, 退款 created_date]
     *
     * @param array $lookups [key => ['store_id', 'platform_order_id', 'created_date']]
     * @return array [store_id:platform_order_id => ['order_created_date' => ..., 'order_paid_date' => ...]]
     */
    protected function queryOrderDates(array $lookups): array
    {
        $orders = Order::query()
            ->where(function ($query) use ($lookups) {
                foreach ($lookups as $lookup) {
                    $createdDate = Carbon::parse($lookup['created_date']);
                    $query->orWhere(function ($q) use ($lookup, $createdDate) {
                        $q->where('store_id', $lookup['store_id'])
                          ->where('platform_order_id', $lookup['platform_order_id'])
                          ->whereBetween('created_date', [
                              $createdDate->copy()->subMonths(4),
                              $createdDate,
                          ]);
                    });
                }
            })
            ->get(['store_id', 'platform_order_id', 'created_date', 'paid_date']);

        $map = [];
        foreach ($orders as $order) {
            $key = $order->store_id . ':' . $order->platform_order_id;
            $map[$key] = [
                'order_created_date' => $order->created_date,
                'order_paid_date' => $order->paid_date,
            ];
        }

        return $map;
    }

    /**
     * 将 Shopee 退款状态映射为系统退款状态 ID
     *
     * @param string $platform_status Shopee ReturnStatus 字符串
     * @return int
     */
    public function getRefundStatusId(string $platform_status): int
    {
        $map = $this->refundStatusMap();
        return $map[$platform_status] ?? RefundStatus::APPLIED->value;
    }

    /**
     * Shopee ReturnStatus → 系统 RefundStatus 映射
     *
     * @return array<string, int>
     */
    private function refundStatusMap(): array
    {
        return [
            ShopeeReturnStatus::REQUESTED->value      => RefundStatus::APPLIED->value,
            ShopeeReturnStatus::ACCEPTED->value        => RefundStatus::SELLER_ACCEPTED->value,
            ShopeeReturnStatus::PROCESSING->value      => RefundStatus::SELLER_ACCEPTED->value,
            ShopeeReturnStatus::JUDGING->value         => RefundStatus::SELLER_DISPUTE->value,
            ShopeeReturnStatus::SELLER_DISPUTE->value  => RefundStatus::SELLER_DISPUTE->value,
            ShopeeReturnStatus::CLOSED->value          => RefundStatus::CLOSED->value,
            ShopeeReturnStatus::CANCELLED->value       => RefundStatus::CLOSED->value,
        ];
    }

    /**
     * 根据 Shopee 退款数据判断退款类型
     *
     * @param array $record 单条退款原始数据
     * @return int
     */
    public function getRefundTypeId(array $record): int
    {
        $needs_logistics = $record['needs_logistics'] ?? false;

        if ($needs_logistics) {
            return RefundType::RETURN_AND_REFUND->value;
        }

        return RefundType::RETURN_BEFORE_SHIPPING->value;
    }


    /**
     * Shopee 的退款包含子项，因此 确定有父退款
     */
    public function hasParentRefund(): bool
    {
        return true;
    }

}
