<?php
// +----------------------------------------------------------------------
// | onezan-admin 快速开发的管理平台
// +----------------------------------------------------------------------
// | 官方网址：https://www.onezan.cn
// +----------------------------------------------------------------------
// | onezan团队 版权所有 开源版本可自由商用
// +----------------------------------------------------------------------
// | Author: 543885307@qq.com
// +----------------------------------------------------------------------
namespace app\service\domain\channel;

use Core\service\registry\MessageRegistry;
use Core\service\BaseCoreService;

/**
 * Core Channel Catalog Service
 * @package app\service\domain\channel
 */
class CoreChannelCatalogService extends BaseCoreService
{
    public const SECRET_MASK = '******';

    private static array $DRIVER_NAME_MAP = [
        'weapp_subscribe' => '微信小程序订阅消息',
        'wechat_template' => '公众号模板消息',
        'alipay_template' => '支付宝模板消息',
        'sms' => '短信通知',
        'email' => '邮件通知',
    ];

    private static array $CHANNEL_DRIVER_TYPES = [
        'weapp' => ['weapp_subscribe', 'sms', 'email'],
        'wechat' => ['wechat_template', 'sms', 'email'],
        'aliapp' => ['alipay_template', 'sms', 'email'],
        'h5' => ['sms', 'email'],
        'app' => ['sms', 'email'],
    ];

    private MessageRegistry $messageRegistry;

    public function __construct(\think\App $app, MessageRegistry $messageRegistry)
    {
        parent::__construct($app);
        $this->messageRegistry = $messageRegistry;
    }

    /**
     * 获取渠道目录
     * @return array
     */
    public function channels(): array
    {
        $driverCatalog = $this->notifyDrivers();

        $byType = [];
        foreach ($driverCatalog as $key => $def) {
            $type = (string)($def['driver_type'] ?? '');
            if ($type !== '') {
                $byType[$type][] = $key;
            }
        }

        $driversFor = fn(array $types) => array_values(array_merge(
            ...array_map(fn($t) => $byType[$t] ?? [], $types)
        ));

        return [
            'weapp' => [
                'key' => 'weapp',
                'name' => '微信小程序',
                'scene' => '微信小程序端',
                'icon' => 'iconfont icon-menu-system',
                'sort' => 10,
                'base_fields' => [
                    $this->field('app_id', 'AppID', 'input', true),
                    $this->field('app_secret', 'AppSecret', 'password', true, true),
                    $this->field('original_id', '原始ID'),
                    $this->field('token', 'Token'),
                    $this->field('aes_key', 'EncodingAESKey', 'password', false, true),
                    $this->field('content_security_enabled', '内容安全检测', 'switch'),
                ],
                'payment_providers' => ['wechatpay', 'balance', 'offline'],
                'notify_drivers' => $driversFor(self::$CHANNEL_DRIVER_TYPES['weapp']),
            ],
            'wechat' => [
                'key' => 'wechat',
                'name' => '微信公众号',
                'scene' => '公众号端 OAuth JSAPI 场景',
                'icon' => 'iconfont icon-menu-system',
                'sort' => 20,
                'base_fields' => [
                    $this->field('app_id', 'AppID', 'input', true),
                    $this->field('app_secret', 'AppSecret', 'password', true, true),
                    $this->field('original_id', '原始ID'),
                    $this->field('token', 'Token'),
                    $this->field('aes_key', 'EncodingAESKey', 'password', false, true),
                    $this->field('oauth_redirect_url', 'OAuth 回调域名'),
                ],
                'payment_providers' => ['wechatpay', 'balance', 'offline'],
                'notify_drivers' => $driversFor(self::$CHANNEL_DRIVER_TYPES['wechat']),
            ],
            'aliapp' => [
                'key' => 'aliapp',
                'name' => '支付宝小程序',
                'scene' => '支付宝小程序端',
                'icon' => 'iconfont icon-menu-system',
                'sort' => 30,
                'base_fields' => [
                    $this->field('app_id', 'AppID', 'input', true),
                    $this->field('private_key', '应用私钥', 'textarea', true, true),
                    $this->field('alipay_public_key', '支付宝公钥', 'textarea', true, true),
                    $this->field('gateway', '网关地址'),
                ],
                'payment_providers' => ['alipay', 'balance', 'offline'],
                'notify_drivers' => $driversFor(self::$CHANNEL_DRIVER_TYPES['aliapp']),
            ],
            'h5' => [
                'key' => 'h5',
                'name' => 'H5',
                'scene' => '移动端网页 / H5 场景',
                'icon' => 'iconfont icon-menu-system',
                'sort' => 40,
                'base_fields' => [
                    $this->field('site_name', '站点名称'),
                    $this->field('bind_domain', '绑定域名'),
                    $this->field('callback_domain', '回调域名'),
                ],
                'payment_providers' => ['wechatpay', 'alipay', 'balance', 'offline'],
                'notify_drivers' => $driversFor(self::$CHANNEL_DRIVER_TYPES['h5']),
            ],
            'app' => [
                'key' => 'app',
                'name' => 'APP',
                'scene' => '移动端 App 原生场景',
                'icon' => 'iconfont icon-menu-system',
                'sort' => 50,
                'base_fields' => [
                    $this->field('android_package', 'Android 包名'),
                    $this->field('ios_bundle_id', 'iOS Bundle ID'),
                    $this->field('scheme', 'URL Scheme'),
                    $this->field('universal_link', 'Universal Link'),
                ],
                'payment_providers' => ['wechatpay', 'alipay', 'balance', 'offline'],
                'notify_drivers' => $driversFor(self::$CHANNEL_DRIVER_TYPES['app']),
            ],
        ];
    }

    /**
     * 获取支付方式目录
     * @return array
     */
    public function paymentProviders(): array
    {
        return [
            'balance' => [
                'key' => 'balance',
                'name' => '余额支付',
                'sort' => 30,
                'description' => '用户使用账户余额直接完成支付',
                'rules_hint' => '支付金额不得超过用户余额',
                'fields' => [
                    $this->field('min_amount', '最低支付金额', 'input'),
                    $this->field('max_amount', '最高支付金额', 'input'),
                    $this->field('tips', '支付提示文案', 'textarea'),
                ],
            ],
            'offline' => [
                'key' => 'offline',
                'name' => '线下支付',
                'sort' => 40,
                'description' => '用户通过线下转账完成支付后由管理员确认',
                'rules_hint' => '需填写收款账户信息供用户查看',
                'fields' => [
                    $this->field('collection_name', '收款人姓名', 'input'),
                    $this->field('collection_bank', '收款银行', 'input'),
                    $this->field('collection_account', '收款账号', 'input'),
                    $this->field('collection_desc', '收款说明', 'textarea'),
                    $this->field('min_amount', '最低支付金额', 'input'),
                    $this->field('max_amount', '最高支付金额', 'input'),
                ],
            ],
            'wechatpay' => [
                'key' => 'wechatpay',
                'name' => '微信支付',
                'sort' => 10,
                'fields' => [
                    $this->field('app_id', 'AppID'),
                    $this->field('mch_id', '商户号', 'input', true),
                    $this->field('v3_secret_key', 'V3 密钥', 'password', true, true),
                    $this->field('merchant_cert', '商户证书', 'cert_upload', true, true),
                    $this->field('private_key', '私钥', 'cert_upload', true, true),
                ],
            ],
            'alipay' => [
                'key' => 'alipay',
                'name' => '支付宝支付',
                'sort' => 20,
                'fields' => [
                    $this->field('app_id', 'AppID', 'input', true),
                    $this->field('private_key', '应用私钥', 'cert_upload', true, true),
                    $this->field('alipay_public_key', '支付宝公钥', 'cert_upload', true, true),
                    $this->field('return_url', '同步回调地址'),
                    $this->field('gateway', '网关地址'),
                ],
            ],
        ];
    }

    /**
     * 获取通知
     * @return array
     */
    public function notifyDrivers(): array
    {
        $drivers = $this->coreNotifyDrivers();

        foreach ($this->messageRegistry->allRaw() as $fileData) {
            $messages = $fileData['messages'] ?? [];
            foreach ($messages as $msg) {
                $scene = (string)($msg['scene'] ?? '');
                $msgDrivers = $msg['drivers'] ?? [];
                if ($scene === '' || !is_array($msgDrivers)) {
                    continue;
                }
                $title = (string)($msg['title'] ?? '');

                foreach ($msgDrivers as $driverType => $config) {
                    $driverType = (string)$driverType;
                    if (!is_array($config)) {
                        continue;
                    }
                    $key = $scene . '.' . $driverType;
                    if (isset($drivers[$key])) {
                        continue;
                    }

                    $drivers[$key] = [
                        'key' => $key,
                        'name' => $title,
                        'sort' => (int)($config['sort'] ?? 99),
                        'scene_name' => $title,
                        'driver_type' => $driverType,
                        'driver_name' => self::$DRIVER_NAME_MAP[$driverType] ?? $driverType,
                        'scene_key' => $scene,
                        'template_sync' => (int)($config['template_sync'] ?? 0),
                        'sync_tip' => (string)($config['sync_tip'] ?? ''),
                        'format_desc' => (string)($config['format_desc'] ?? ''),
                        'var_mapping' => $config['var_mapping'] ?? [],
                        'example_lines' => $config['example_lines'] ?? [],
                        'fields' => $config['fields'] ?? [],
                    ];
                }
            }
        }

        return $drivers;
    }

    /**
     * 获取核心通知驱动目录
     * @return array
     */
    private function coreNotifyDrivers(): array
    {
        return [
            'auth_notice.sms' => [
                'key' => 'auth_notice.sms',
                'name' => '账号通知',
                'sort' => 5,
                'scene_name' => '账号通知',
                'driver_type' => 'sms',
                'driver_name' => '短信通知',
                'scene_key' => 'auth_notice',
                'template_sync' => 0,
                'sync_tip' => '',
                'format_desc' => '短信由系统设置-短信接口中配置的服务商统一发送',
                'var_mapping' => [],
                'example_lines' => ['{username} {login_time} IP: {login_ip}'],
                'fields' => [
                    $this->field('template_id', '模板ID / Code'),
                ],
            ],
            'auth_notice.email' => [
                'key' => 'auth_notice.email',
                'name' => '账号通知',
                'sort' => 6,
                'scene_name' => '账号通知',
                'driver_type' => 'email',
                'driver_name' => '邮件通知',
                'scene_key' => 'auth_notice',
                'template_sync' => 0,
                'sync_tip' => '',
                'format_desc' => '邮件由系统设置-邮件接口中配置的 SMTP 统一发送',
                'var_mapping' => [],
                'example_lines' => [],
                'fields' => [
                    $this->field('subject_template', '邮件标题模板'),
                    $this->field('body_template', '邮件正文 HTML 模板'),
                ],
            ],
        ];
    }

    /**
     * 检查渠道是否存在
     * @param string $channel
     * @return bool
     */
    public function hasChannel(string $channel): bool
    {
        return isset($this->channels()[$channel]);
    }

    /**
     * 获取通知驱动字段
     * @param string $key
     * @param string $label
     * @param string $component
     * @param bool $required
     * @param bool $secret
     * @return array
     */
    private function field(
        string $key,
        string $label,
        string $component = 'input',
        bool $required = false,
        bool $secret = false
    ): array {
        return [
            'key' => $key,
            'label' => $label,
            'component' => $component,
            'required' => $required ? 1 : 0,
            'secret' => $secret ? 1 : 0,
        ];
    }
}
