<?php

declare(strict_types=1);

namespace app\common\service;

use app\common\library\scrm\AbstractScrmSpider;
use app\common\library\scrm\ScrmSpiderInterface;
use app\common\library\scrm\spider\A2cSpider;
use app\common\library\scrm\spider\ChatknowSpider;
use app\common\library\scrm\spider\HaiwangSpider;
use app\common\library\scrm\spider\HuojianSpider;
use app\common\library\scrm\spider\SsCustomerSpider;
use app\common\library\scrm\spider\WhatshubSpider;
use app\common\library\scrm\spider\XingheSpider;

/**
 * 工单类型 -> 云控蜘蛛工厂
 *
 * 新增云控类型：在 spider/ 下新增类并在此注册 ticket_type => Class
 */
class SplitScrmSpiderFactory
{
    /** @var array<string, class-string<ScrmSpiderInterface>> */
    private const MAP = [
        'a2c'         => A2cSpider::class,
        'haiwang'     => HaiwangSpider::class,
        'huojian'     => HuojianSpider::class,
        'xinghe'      => XingheSpider::class,
        'ss_customer' => SsCustomerSpider::class,
        'chatknow'    => ChatknowSpider::class,
        'whatshub'    => WhatshubSpider::class,
        // ceo_scrm 等未实现类型：新增 spider 类后在此注册
    ];

    /**
     * API 优先同步类型：常态走 PHP cURL，不占 Node Real Browser 槽位
     *
     * Whatshub 已改为混合同步（cURL 号码 + Node statistics），需走 Node 队列门禁。
     *
     * @var list<string>
     */
    private const API_FIRST_SYNC_TYPES = [
    ];

    /**
     * @return class-string<ScrmSpiderInterface>|null
     */
    public static function resolveClass(string $ticketType): ?string
    {
        $ticketType = trim($ticketType);
        return self::MAP[$ticketType] ?? null;
    }

    /**
     * 是否已实现蜘蛛
     */
    public static function isSupported(string $ticketType): bool
    {
        return self::resolveClass($ticketType) !== null;
    }

    /**
     * 已注册且已实现蜘蛛的类型列表
     *
     * @return list<string>
     */
    public static function listSupportedTypes(): array
    {
        return array_keys(self::MAP);
    }

    /**
     * 是否 API 优先类型（调度层可并行投递且不占 Node 队列）
     */
    public static function isApiFirstSyncType(string $ticketType): bool
    {
        return in_array(trim($ticketType), self::API_FIRST_SYNC_TYPES, true);
    }

    /**
     * @return list<string>
     */
    public static function listApiFirstSyncTypes(): array
    {
        return self::API_FIRST_SYNC_TYPES;
    }

    /**
     * 同步是否依赖 Node Headless（纯 PHP cURL 等为 false）
     */
    public static function requiresNode(string $ticketType): bool
    {
        $class = self::resolveClass($ticketType);
        if ($class === null) {
            return true;
        }

        return is_subclass_of($class, AbstractScrmSpider::class);
    }

    /**
     * @return list<string>
     */
    public static function listDirectSyncTypes(): array
    {
        $types = [];
        foreach (self::listSupportedTypes() as $ticketType) {
            if (!self::requiresNode($ticketType)) {
                $types[] = $ticketType;
            }
        }

        return $types;
    }

    /**
     * @return list<string>
     */
    public static function listNodeSyncTypes(): array
    {
        $types = [];
        foreach (self::listSupportedTypes() as $ticketType) {
            if (self::requiresNode($ticketType)) {
                $types[] = $ticketType;
            }
        }

        return $types;
    }

    /**
     * @return ScrmSpiderInterface|null
     */
    public static function create(
        string $ticketType,
        string $pageUrl,
        string $account = '',
        string $password = '',
        string $nodeHost = ''
    ): ?ScrmSpiderInterface {
        $class = self::resolveClass($ticketType);
        if ($class === null) {
            return null;
        }
        $host = $nodeHost !== '' ? $nodeHost : SplitSyncConfigService::getNodeHost();
        return new $class($pageUrl, $account, $password, $host);
    }
}
