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

use app\service\domain\channel\driver\wechat\EasywechatFactory;
use think\App;
use think\facade\Log;


/**
 * Weapp Subscribe Driver
 * @package app\service\domain\notification\driver
 */
class WeappSubscribeDriver implements NotificationDriverInterface
{
    private App $app;

    /**
     * @param App $app
     */
    public function __construct(App $app)
    {
        $this->app = $app;
    }


    /**
     * 返回驱动类型标识
     * @return string
     */
    public function driverType(): string
    {
        return 'weapp_subscribe';
    }


    /**
     * 返回驱动显示名称
     * @return string
     */
    public function name(): string
    {
        return '';
    }


    /**
     * 发送微信小程序订阅消息
     * @param array $to 接收方信息（openid）
     * @param string $templateId 模板ID
     * @param array $data 模板变量数据
     * @param array $config 驱动配置（page/var_mapping/channel_config）
     * @return array
     */
    public function send(array $to, string $templateId, array $data, array $config): array
    {
        $openid = (string)($to['openid'] ?? '');
        if ($openid === '') {
            return ['code' => 0, 'msg' => '', 'raw' => []];
        }

        if ($this->app->isDebug()) {
            Log::info('', [
                'openid' => $openid,
                'template_id' => $templateId,
                'data' => $data,
            ]);
            return ['code' => 0, 'msg' => 'ok[test]', 'raw' => ['mock' => true]];
        }

        try {
            $channelConfig = $config['channel_config'] ?? [];
            $factory = $this->app->make(EasywechatFactory::class);
            $miniApp = $factory->miniApp($channelConfig);

            $result = $miniApp->getClient()->postJson('/cgi-bin/message/subscribe/send', [
                'touser' => $openid,
                'template_id' => $templateId,
                'page' => (string)($config['page'] ?? ''),
                'data' => $this->formatWeappData($data, $config),
            ]);

            $body = $result->toArray();
            $errCode = (int)($body['errcode'] ?? -1);
            if ($errCode === 0) {
                return ['code' => 0, 'msg' => 'ok', 'raw' => $body];
            }

            Log::warning('', ['errcode' => $errCode, 'errmsg' => $body['errmsg'] ?? '']);
            return ['code' => 1, 'msg' => (string)($body['errmsg'] ?? ''), 'raw' => $body];
        } catch (\Throwable $e) {
            Log::error('' . $e->getMessage());
            return ['code' => 1, 'msg' => $e->getMessage(), 'raw' => []];
        }
    }


    /**
     * 格式化微信小程序订阅消息数据
     * 优先使用var_mapping映射，否则调用formatData兜底
     * @param array $data 消息数据
     * @param array $config 驱动配置（含var_mapping）
     * @return array 格式化后的数据
     */
    private function formatWeappData(array $data, array $config): array
    {
        $varMapping = $config['var_mapping'] ?? null;

        if (is_array($varMapping) && !empty($varMapping)) {
            $formatted = [];
            foreach ($varMapping as $entry) {
                $field = (string)($entry['field'] ?? '');
                $bindVar = (string)($entry['bind_var'] ?? '');
                if ($field === '') continue;
                $value = ($bindVar !== '' && isset($data[$bindVar])) ? (string)$data[$bindVar] : '';
                $formatted[$field] = ['value' => $value];
            }
            return $formatted;
        }

        return $this->formatData($data);
    }

    /**
     * 将消息数据批量转为微信格式（field => {value: ...}）
     * @param array $data 消息数据
     * @return array 格式化后的数据
     */
    private function formatData(array $data): array
    {
        $formatted = [];
        foreach ($data as $key => $value) {
            $formatted[$key] = ['value' => (string)$value];
        }
        return $formatted;
    }
}