<?php

declare(strict_types=1);

namespace App\Entity\Parse;

use App\Model\Platform;
use Hyperf\Amqp\Message\ConsumerMessageInterface;
use Hyperf\Contract\ConfigInterface;
use Hyperf\Stringable\Str;
use InvalidArgumentException;
use Psr\Container\ContainerInterface;
use PhpAmqpLib\Message\AMQPMessage;

/**
 * EntityParseFactory 工厂类
 *
 * 自动根据消息特征创建对应平台的 EntityParse 实例
 * 使用静态方法调用，无需依赖注入
 *
 * @example
 * // 基础用法
 * use App\Entity\Parse\EntityParseFactory;
 *
 * $parser = EntityParseFactory::createFromMessage($message);
 * $entity = $parser->entityMatch($message);
 * $rawData = json_decode($message->getBody(), true);
 * $entity = $parser->entityMap($rawData, $entity);
 * $entity->save();
 *
 * // 指定实体类型（覆盖自动提取）
 * $parser = EntityParseFactory::createFromMessage($message, 'order');
 *
 * 命名约定（推荐方式）：
 * - 创建符合命名约定的 Parser 类，工厂自动查找
 * - 类名：{Entity}
 * - 命名空间：App\Platform\{Platform}\EntityParse
 * - 示例：App\Platform\Shopee\EntityParse\Order
 *
 * 平台名称来源：
 * - 从 platforms 表中根据 platform_id 查询 name 字段
 * - 示例：platform_id=25 -> name='Shopee' -> App\Platform\Shopee\EntityParse\Order
 *
 * 如果找不到对应的 Parser 类，将抛出 InvalidArgumentException
 *
 * 配置文件（可选）：
 * - 如需覆盖默认行为，可在 config/autoload/entity_parse.php 中配置
 * - 配置格式：[platform_id => ['entity_type' => ParserClass]]
 * - 支持通配符 '*' 匹配所有实体类型
 */
class EntityParseFactory
{
    /**
     * 平台与 Parser 类的映射表
     * 格式：[platform_id => ['entity_type' => ParserClass]]
     * 示例：[25 => ['order' => ShopeeOrderParser, 'product' => ShopeeProductParser]]
     *
     * @var array<int, array<string, class-string<EntityParse>>>
     */
    private static array $registry = [];

    /**
     * 容器实例
     */
    private static ?ContainerInterface $container = null;

    /**
     * 配置实例
     */
    private static ?ConfigInterface $config = null;

    /**
     * 设置容器（由框架注入）
     *
     * @param ContainerInterface $container
     * @return void
     */
    public static function setContainer(ContainerInterface $container): void
    {
        self::$container = $container;
        self::$config = $container->get(ConfigInterface::class);
        self::loadConfig();
    }

    /**
     * 从配置文件加载平台映射
     *
     * @return void
     */
    private static function loadConfig(): void
    {
        if (!self::$config) {
            return;
        }

        $parsers = self::$config->get('entity_parse.platforms', []);

        foreach ($parsers as $platform => $entities) {
            foreach ($entities as $entityType => $parserClass) {
                self::register($platform, $entityType, $parserClass);
            }
        }
    }

    /**
     * 根据消息自动创建 Parser 实例（静态方法）
     *
     * @param AMQPMessage $message
     * @param string|null $entityType 实体类型（可选，如果不指定则从 payload 中提取）
     * @return EntityParseInterface
     * @throws InvalidArgumentException
     */
    public static function createFromMessage(
        AMQPMessage $message,
        ?string $entityType = null
    ): EntityParseInterface {
        // 1. 从消息体中解析数据
        $data = json_decode($message->getBody(), true);

        if (!is_array($data)) {
            throw new InvalidArgumentException('Invalid message body: expected JSON array');
        }

        // 2. 从 meta 中提取 platform_id
        if (!isset($data['meta']['platform_id'])) {
            throw new InvalidArgumentException('Missing required field: platform_id');
        }
        $platformId = (int) $data['meta']['platform_id'];

        // 3. 如果未指定实体类型，从 routing key 中提取
        if ($entityType === null) {
            $entityType = self::extractEntityTypeFromData($data, $message);
        }

        // 4. 获取对应的 Parser 类
        $parserClass = self::resolveParserClass($platformId, $entityType);

        // 5. 创建并返回 Parser 实例，传递解析后的数据和消息对象
        return $parserClass::create($data, $message);
    }

    /**
     * 从路由键中提取实体类型
     *
     * @param array $data
     * @param AMQPMessage $message
     * @return string
     */
    private static function extractEntityTypeFromData(array $data, AMQPMessage $message): string
    {
        // 优先从 routing key 中提取
        $routingKey = $message->getRoutingKey();

        $entityType = Str::of($routingKey)
            ->before('.')
            ->lower()
            ->toString();

        if (!empty($entityType)) {
            return $entityType;
        }

        throw new InvalidArgumentException("Cannot extract entity type from routing key: {$routingKey}");
    }

    /**
     * 解析 Parser 类名
     *
     * 优先级：
     * 1. 手动注册的映射
     * 2. 配置文件中的映射
     * 3. 命名约定自动查找
     *
     * @param int $platformId
     * @param string $entityType
     * @return class-string<EntityParse>
     * @throws InvalidArgumentException
     */
    private static function resolveParserClass(int $platformId, string $entityType): string
    {
        // 1. 检查手动注册的映射
        if (isset(self::$registry[$platformId][$entityType])) {
            return self::$registry[$platformId][$entityType];
        }

        // 2. 检查通配符映射（支持 * 匹配所有实体类型）
        if (isset(self::$registry[$platformId]['*'])) {
            return self::$registry[$platformId]['*'];
        }

        // 3. 使用命名约定自动查找
        $parserClass = self::findByConvention($platformId, $entityType);

        if ($parserClass) {
            // 自动注册以提高后续性能
            self::register($platformId, $entityType, $parserClass);
            return $parserClass;
        }

        throw new InvalidArgumentException(
            "Cannot find parser for platform_id '{$platformId}' and entity '{$entityType}'. " .
            "Please register it using EntityParseFactory::register() or create a parser class following the naming convention."
        );
    }

    /**
     * 根据命名约定查找 Parser 类
     *
     * 命名约定：
     * - 类名：{Entity}
     * - 命名空间：App\Platform\{Platform}\EntityParse
     *
     * 示例：
     * - platform_id: 25 (Shopee), entity: order -> App\Platform\Shopee\EntityParse\Order
     * - platform_id: 2 (Tmall), entity: product -> App\Platform\Tmall\EntityParse\Product
     *
     * @param int $platformId
     * @param string $entityType
     * @return class-string<EntityParse>|null
     */
    private static function findByConvention(int $platformId, string $entityType): ?string
    {
        // 从数据库查询平台信息
        $platform = Platform::find($platformId);

        if (!$platform || !isset($platform->name)) {
            return null;
        }

        // 使用平台名称构建类名（处理多词平台名，如 "Amazon Japan" -> "AmazonJapan"）
        $platformPascal = Str::of($platform->name)
            ->replace(' ', '')  // 移除空格
            ->studly()          // 转换为 StudlyCase
            ->toString();

        $entityPascal = Str::of($entityType)->studly()->toString();

        // 标准命名：App\Platform\Shopee\EntityParse\Order
        $class = "App\\Platform\\{$platformPascal}\\EntityParse\\{$entityPascal}";

        if (class_exists($class) && is_subclass_of($class, EntityParse::class)) {
            return $class;
        }

        return null;
    }

    /**
     * 手动注册平台与 Parser 的映射关系
     *
     * @param int $platformId 平台 ID（如：25 表示 Shopee）
     * @param string $entityType 实体类型（小写），使用 '*' 表示匹配所有实体类型
     * @param class-string<EntityParse> $parserClass Parser 类名
     * @return void
     * @throws InvalidArgumentException
     */
    public static function register(int $platformId, string $entityType, string $parserClass): void
    {
        // 验证 Parser 类是否存在
        if (!class_exists($parserClass)) {
            throw new InvalidArgumentException("Parser class '{$parserClass}' does not exist");
        }

        // 验证 Parser 类是否继承自 EntityParse
        if (!is_subclass_of($parserClass, EntityParse::class)) {
            throw new InvalidArgumentException(
                "Parser class '{$parserClass}' must extend " . EntityParse::class
            );
        }

        // 注册映射
        self::$registry[$platformId][$entityType] = $parserClass;
    }

    /**
     * 批量注册平台映射
     *
     * @param array<int, array<string, class-string<EntityParse>>> $mappings
     * @return void
     */
    public static function registerBatch(array $mappings): void
    {
        foreach ($mappings as $platformId => $entities) {
            foreach ($entities as $entityType => $parserClass) {
                self::register($platformId, $entityType, $parserClass);
            }
        }
    }

    /**
     * 获取所有已注册的映射
     *
     * @return array<int, array<string, class-string<EntityParse>>>
     */
    public static function getRegistry(): array
    {
        return self::$registry;
    }

    /**
     * 清空所有注册的映射（主要用于测试）
     *
     * @return void
     */
    public static function clearRegistry(): void
    {
        self::$registry = [];
    }

    /**
     * 检查指定平台和实体类型的 Parser 是否已注册
     *
     * @param int $platformId
     * @param string $entityType
     * @return bool
     */
    public static function hasParser(int $platformId, string $entityType): bool
    {
        return isset(self::$registry[$platformId][$entityType])
            || isset(self::$registry[$platformId]['*']);
    }
}
