<?php

declare(strict_types=1);

namespace App\Entity\Parse\Traits;

use App\Model\Model as Entity;
use App\Model\Platform;
use InvalidArgumentException;
use Hyperf\Stringable\Str;
use PhpAmqpLib\Message\AMQPMessage;

/**
 * EntityParseHelper Trait
 *
 * 提供通用的消息解析辅助方法
 */
trait EntityParseHelper
{
    /**
     * 从消息体中提取平台信息
     *
     * 从消息体的 meta.platform_id 获取平台 ID，查询 Platform
     *
     * @param AMQPMessage $message
     * @return Platform
     * @throws InvalidArgumentException
     */
    protected function extractPlatformFromExchange(AMQPMessage $message): Platform
    {
        $data = json_decode($message->getBody(), true);

        $platformId = $data['meta']['platform_id'] ?? null;

        if (!$platformId) {
            throw new InvalidArgumentException("Missing platform_id in message meta");
        }

        $platform = Platform::find($platformId);

        if (!$platform) {
            throw new InvalidArgumentException("Platform with id '{$platformId}' does not exist!");
        }

        return $platform;
    }

    /**
     * 从 routing key 中提取实体类型
     *
     * 规则：routing key 格式为 "entity.platform"
     * 例如：order.tmall -> Order 实体
     *
     * @param AMQPMessage $message
     * @return Entity
     * @throws InvalidArgumentException
     */
    protected function extractEntityFromRoutingKey(AMQPMessage $message): Entity
    {
        $entityName = Str::of($message->getRoutingKey())
            ->before('.')
            ->ucfirst()
            ->toString();

        $entityClass = "App\\Model\\{$entityName}";

        if (!class_exists($entityClass)) {
            throw new InvalidArgumentException("Entity class '{$entityClass}' does not exist");
        }

        $entity = new $entityClass();

        if (!$entity instanceof Entity) {
            throw new InvalidArgumentException("Class '{$entityClass}' is not an instance of Entity");
        }

        return $entity;
    }

    /**
     * 从消息体中提取 JSON 数据
     *
     * @param AMQPMessage $message
     * @return array
     * @throws InvalidArgumentException
     */
    protected function extractMessageData(AMQPMessage $message): array
    {
        $body = $message->getBody();

        if (empty($body)) {
            throw new InvalidArgumentException('Message body is empty');
        }

        $data = json_decode($body, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            throw new InvalidArgumentException('Invalid JSON in message body: ' . json_last_error_msg());
        }

        return $data;
    }

    /**
     * 从消息数据中提取唯一标识符
     *
     * 优先级：id > unique_id > 其他自定义字段
     *
     * @param array $data
     * @param string|null $customField 自定义标识符字段名
     * @return string|int
     * @throws InvalidArgumentException
     */
    protected function extractUniqueIdentifier(array $data, ?string $customField = null): string|int
    {
        // 优先使用自定义字段
        if ($customField !== null && isset($data[$customField])) {
            return $data[$customField];
        }

        // 默认查找 id
        if (isset($data['id'])) {
            return $data['id'];
        }

        // 查找 unique_id
        if (isset($data['unique_id'])) {
            return $data['unique_id'];
        }

        throw new InvalidArgumentException('Cannot extract unique identifier from message data');
    }

    /**
     * 从消息数据中安全地提取字段值
     *
     * @param array $data
     * @param string $field
     * @param mixed $default
     * @return mixed
     */
    protected function getDataField(array $data, string $field, mixed $default = null): mixed
    {
        return $data[$field] ?? $default;
    }

    /**
     * 验证消息数据中的必需字段
     *
     * @param array $data
     * @param array $requiredFields
     * @return void
     * @throws InvalidArgumentException
     */
    protected function validateRequiredFields(array $data, array $requiredFields): void
    {
        $missingFields = [];

        foreach ($requiredFields as $field) {
            if (!isset($data[$field])) {
                $missingFields[] = $field;
            }
        }

        if (!empty($missingFields)) {
            throw new InvalidArgumentException(
                'Missing required fields: ' . implode(', ', $missingFields)
            );
        }
    }
}
