<?php

namespace Kylin\Sms;

use InvalidArgumentException;
use Kylin\Sms\Contracts\GatewayInterface;
use Kylin\Sms\Exceptions\GatewayNotFoundException;

/**
 * 短信管理器
 * 
 * 负责管理和调度各短信服务商网关，提供统一的短信发送接口
 * 支持动态切换网关、批量发送、模板发送等功能
 */
class SmsManager
{
    /**
     * 已解析的网关实例缓存
     */
    protected array $resolvedGateways = [];

    /**
     * 网关类映射表
     * 
     * 将网关驱动名称映射到对应的网关类
     */
    protected array $gatewayClasses = [
        // 云服务商
        'aliyun' => Gateways\AliyunGateway::class,
        'tencent' => Gateways\TencentGateway::class,
        'huawei' => Gateways\HuaweiGateway::class,
        'baidu' => Gateways\BaiduGateway::class,
        'volcengine' => Gateways\VolcengineGateway::class,
        'ucloud' => Gateways\UcloudGateway::class,
        'qiniu' => Gateways\QiniuGateway::class,
        'sendcloud' => Gateways\SendcloudGateway::class,
        
        // 专业短信服务商
        'yunpian' => Gateways\YunpianGateway::class,
        'submail' => Gateways\SubmailGateway::class,
        'luosimao' => Gateways\LuosimaoGateway::class,
        'ronglianyun' => Gateways\RonglianyunGateway::class,
        'rongcloud' => Gateways\RongcloudGateway::class,
        'yunzhixun' => Gateways\YunzhixunGateway::class,
        'netease' => Gateways\NeteaseGateway::class,
        
        // 传统短信平台
        'huyi' => Gateways\HuyiGateway::class,
        'juhe' => Gateways\JuheGateway::class,
        'huaxin' => Gateways\HuaxinGateway::class,
        'chuanglan253' => Gateways\Chuanglan253Gateway::class,
        'chuanglanyunzhi' => Gateways\ChuanglanyunzhiGateway::class,
        'tianyi' => Gateways\TianyiGateway::class,
        'kaixintong' => Gateways\KaixintongGateway::class,
        'ue35' => Gateways\Ue35Gateway::class,
        'smsbao' => Gateways\SmsbaoGateway::class,
        'tiniyo' => Gateways\TiniyoGateway::class,
        'moduyun' => Gateways\ModuyunGateway::class,
        
        // 融合云平台
        'rongheyun' => Gateways\RongheyunGateway::class,
        'zhiziyun' => Gateways\ZhiziyunGateway::class,
        'rongheyunxin' => Gateways\RongheyunxinGateway::class,
        'tianruiyun' => Gateways\TianruiyunGateway::class,
        'shidaihulian' => Gateways\ShidaihulianGateway::class,
        
        // 运营商云服务
        'mas' => Gateways\MasGateway::class,
        'ctyun' => Gateways\CtyunGateway::class,
        'weiquyun' => Gateways\WeiquyunGateway::class,
    ];

    /**
     * 构造函数
     * 
     * @param mixed $app Laravel 应用容器
     */
    public function __construct(
        protected $app
    ) {}

    /**
     * 获取网关实例
     * 
     * 根据名称获取或解析网关实例，支持缓存
     * 
     * @param string|null $name 网关名称，为空时使用默认网关
     * @return GatewayInterface 网关实例
     * @throws GatewayNotFoundException 网关未配置或不存在时抛出异常
     */
    public function gateway(?string $name = null): GatewayInterface
    {
        $name = $name ?: $this->getDefaultGateway();

        if (isset($this->resolvedGateways[$name])) {
            return $this->resolvedGateways[$name];
        }

        return $this->resolvedGateways[$name] = $this->resolveGateway($name);
    }

    /**
     * 解析网关实例
     * 
     * 根据配置创建网关实例
     * 
     * @param string $name 网关名称
     * @return GatewayInterface 网关实例
     * @throws GatewayNotFoundException 网关未配置或不存在时抛出异常
     */
    protected function resolveGateway(string $name): GatewayInterface
    {
        $config = $this->app['config']->get("sms.gateways.{$name}", []);

        if (empty($config)) {
            throw new GatewayNotFoundException("短信网关 [{$name}] 未配置。");
        }

        $driver = $config['driver'] ?? $name;

        $gatewayClass = $this->getGatewayClass($driver);

        if (!class_exists($gatewayClass)) {
            throw new GatewayNotFoundException("短信网关类 [{$gatewayClass}] 不存在。");
        }

        return new $gatewayClass($config);
    }

    /**
     * 获取网关类名
     * 
     * 根据驱动名称获取对应的网关类
     * 
     * @param string $driver 驱动名称
     * @return string 网关类名
     * @throws InvalidArgumentException 不支持的驱动时抛出异常
     */
    protected function getGatewayClass(string $driver): string
    {
        return $this->gatewayClasses[$driver] ?? throw new InvalidArgumentException("不支持的短信网关驱动: {$driver}");
    }

    /**
     * 获取默认网关名称
     * 
     * @return string 默认网关名称
     */
    protected function getDefaultGateway(): string
    {
        return $this->app['config']->get('sms.default', 'aliyun');
    }

    /**
     * 扩展网关
     * 
     * 动态注册新的网关类
     * 
     * @param string $name 网关名称
     * @param string $gatewayClass 网关类名
     * @return self 支持链式调用
     */
    public function extend(string $name, string $gatewayClass): self
    {
        $this->gatewayClasses[$name] = $gatewayClass;
        return $this;
    }

    /**
     * 发送短信
     * 
     * 发送普通短信内容
     * 
     * @param string $to 接收手机号
     * @param string $content 短信内容
     * @param array $data 附加数据（如签名、模板参数等）
     * @param string|null $gateway 网关名称，为空时使用默认网关
     * @return array 发送结果
     */
    public function send(string $to, string $content, array $data = [], ?string $gateway = null): array
    {
        return $this->gateway($gateway)->send($to, $content, $data);
    }

    /**
     * 发送模板短信
     * 
     * 使用预定义模板发送短信
     * 
     * @param string $to 接收手机号
     * @param string $templateId 模板 ID
     * @param array $params 模板参数
     * @param string|null $gateway 网关名称，为空时使用默认网关
     * @return array 发送结果
     */
    public function sendTemplate(string $to, string $templateId, array $params = [], ?string $gateway = null): array
    {
        return $this->gateway($gateway)->sendTemplate($to, $templateId, $params);
    }

    /**
     * 批量发送短信
     * 
     * 向多个手机号发送相同内容的短信
     * 
     * @param array $recipients 接收手机号数组
     * @param string $content 短信内容
     * @param array $data 附加数据
     * @param string|null $gateway 网关名称，为空时使用默认网关
     * @return array 发送结果
     */
    public function sendBatch(array $recipients, string $content, array $data = [], ?string $gateway = null): array
    {
        return $this->gateway($gateway)->sendBatch($recipients, $content, $data);
    }

    /**
     * 动态方法调用
     * 
     * 将未定义的方法调用转发到默认网关
     * 
     * @param string $method 方法名
     * @param array $parameters 参数
     * @return mixed
     */
    public function __call(string $method, array $parameters)
    {
        return $this->gateway()->$method(...$parameters);
    }
}
