<?php
declare(strict_types=1);

const OTP_API_URL = 'https://faka.skiii21hc11.cc/api/order/otp';
const OTP_OUT_TRADE_NO = 'CF20260531175643647617AF4';
const OTP_SECURITY_CODE = '1234';
const OTP_WAIT_MS = 0;

/**
 * 记录接口执行步骤日志。
 */
function logInfo(string $message, array $context = []): void
{
    $contextText = $context === [] ? '' : ' ' . json_encode($context, JSON_UNESCAPED_UNICODE);
    error_log('[INFO] ' . $message . $contextText);
}

/**
 * 对前端提交的邮箱进行基础校验。
 */
function validateEmail(string $email): ?string
{
    logInfo('开始校验邮箱', ['email' => $email]);

    if ($email === '') {
        logInfo('邮箱校验失败：邮箱为空');
        return '请输入邮箱';
    }

    if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
        logInfo('邮箱校验失败：邮箱格式不正确', ['email' => $email]);
        return '邮箱格式不正确';
    }

    logInfo('邮箱校验通过', ['email' => $email]);
    return null;
}

/**
 * 对页面输出内容进行 HTML 转义。
 */
function e(?string $value): string
{
    return htmlspecialchars((string) $value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
}

/**
 * 外部验证码接口返回实体。
 */
final class OtpApiResult
{
    public bool $ok = false;
    public string $message = '';
    public string $email = '';
    public ?string $code = null;
    public ?int $checked = null;
    public ?string $method = null;
    public ?string $folder = null;
    public ?string $subject = null;
    public ?string $receivedDateTime = null;
    public ?string $error = null;
    public int $httpStatus = 0;
    public array $raw = [];

    /**
     * 根据外部 API 的 JSON 数据创建验证码返回实体。
     */
    public static function fromApiResponse(array $data, int $httpStatus): self
    {
        logInfo('开始封装外部验证码接口返回值', ['httpStatus' => $httpStatus]);

        $result = new self();
        $result->ok = (bool) ($data['ok'] ?? false);
        $result->message = (string) ($data['message'] ?? '');
        $result->email = (string) ($data['email'] ?? '');
        $result->code = self::findCode($data);
        $result->checked = isset($data['checked']) ? (int) $data['checked'] : null;
        $result->method = isset($data['method']) ? (string) $data['method'] : null;
        $result->folder = isset($data['folder']) ? (string) $data['folder'] : null;
        $result->subject = isset($data['subject']) ? (string) $data['subject'] : null;
        $result->receivedDateTime = isset($data['receivedDateTime']) ? (string) $data['receivedDateTime'] : null;
        $result->httpStatus = $httpStatus;
        $result->raw = $data;

        logInfo('外部验证码接口返回值封装完成', [
            'ok' => $result->ok,
            'email' => $result->email,
            'hasCode' => $result->code !== null,
        ]);

        return $result;
    }

    /**
     * 创建本地调用失败时的验证码返回实体。
     */
    public static function fromLocalError(string $error, int $httpStatus = 0): self
    {
        logInfo('开始封装本地错误返回值', ['error' => $error, 'httpStatus' => $httpStatus]);

        $result = new self();
        $result->ok = false;
        $result->message = '验证码接口调用失败';
        $result->error = $error;
        $result->httpStatus = $httpStatus;

        logInfo('本地错误返回值封装完成');
        return $result;
    }

    /**
     * 从外部 API 返回数据中提取常见验证码字段。
     */
    private static function findCode(array $data): ?string
    {
        logInfo('开始从外部 API 返回数据中提取验证码字段');

        foreach (['code', 'otp', 'verification_code', 'verificationCode', 'security_code', 'securityCode'] as $key) {
            if (isset($data[$key]) && $data[$key] !== '') {
                logInfo('已从明确字段中提取到验证码', ['field' => $key]);
                return (string) $data[$key];
            }
        }

        if (isset($data['data']) && is_array($data['data'])) {
            foreach (['code', 'otp', 'verification_code', 'verificationCode'] as $key) {
                if (isset($data['data'][$key]) && $data['data'][$key] !== '') {
                    logInfo('已从 data 字段中提取到验证码', ['field' => $key]);
                    return (string) $data['data'][$key];
                }
            }
        }

        logInfo('未在返回数据中提取到验证码字段');
        return null;
    }
}

/**
 * 调用外部 OTP 接口获取邮箱验证码。
 */
function fetchOtpByEmail(string $email): OtpApiResult
{
    logInfo('开始调用外部 OTP 接口', ['email' => $email, 'url' => OTP_API_URL]);

    $payload = [
        'out_trade_no' => OTP_OUT_TRADE_NO,
        'security_code' => OTP_SECURITY_CODE,
        'email' => $email,
        'wait_ms' => OTP_WAIT_MS,
    ];

    logInfo('已组装外部 OTP 接口请求参数', [
        'out_trade_no' => $payload['out_trade_no'],
        'email' => $payload['email'],
        'wait_ms' => $payload['wait_ms'],
    ]);

    if (function_exists('curl_init')) {
        logInfo('检测到 cURL 扩展，准备使用 cURL 调用外部 OTP 接口');
        return fetchOtpByCurl($payload);
    }

    logInfo('未检测到 cURL 扩展，准备使用 PHP HTTP stream 调用外部 OTP 接口');
    return fetchOtpByStream($payload);
}

/**
 * 使用 cURL 调用外部 OTP 接口。
 */
function fetchOtpByCurl(array $payload): OtpApiResult
{
    $ch = curl_init(OTP_API_URL);
    if ($ch === false) {
        logInfo('初始化 cURL 失败');
        return OtpApiResult::fromLocalError('初始化 cURL 失败');
    }

    logInfo('开始设置 cURL 请求头和请求体');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
        CURLOPT_HTTPHEADER => [
            'accept: */*',
            'content-type: application/json',
            'origin: https://faka.skiii21hc11.cc',
            'referer: https://faka.skiii21hc11.cc/',
            'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36',
        ],
        CURLOPT_CONNECTTIMEOUT => 10,
        CURLOPT_TIMEOUT => 30,
    ]);

    logInfo('开始通过 cURL 发送外部 OTP 接口请求');
    $responseBody = curl_exec($ch);
    $curlError = curl_error($ch);
    $httpStatus = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    logInfo('cURL 外部 OTP 接口请求完成', [
        'httpStatus' => $httpStatus,
        'hasCurlError' => $curlError !== '',
        'hasResponseBody' => $responseBody !== false && $responseBody !== '',
    ]);

    if ($responseBody === false) {
        logInfo('外部 OTP 接口请求失败', ['error' => $curlError]);
        return OtpApiResult::fromLocalError($curlError !== '' ? $curlError : '未知 cURL 错误', $httpStatus);
    }

    logInfo('开始解析外部 OTP 接口 JSON 返回');
    return parseOtpApiResponse($responseBody, $httpStatus);
}

/**
 * 使用 PHP HTTP stream 调用外部 OTP 接口。
 */
function fetchOtpByStream(array $payload): OtpApiResult
{
    logInfo('开始设置 HTTP stream 请求参数');

    $httpOptions = [
        'method' => 'POST',
        'header' => implode("\r\n", [
            'accept: */*',
            'content-type: application/json',
            'origin: https://faka.skiii21hc11.cc',
            'referer: https://faka.skiii21hc11.cc/',
            'user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36',
        ]),
        'content' => json_encode($payload, JSON_UNESCAPED_UNICODE),
        'timeout' => 30,
        'ignore_errors' => true,
    ];

    logInfo('开始通过 HTTP stream 发送外部 OTP 接口请求');
    $context = stream_context_create(['http' => $httpOptions]);
    $responseBody = file_get_contents(OTP_API_URL, false, $context);
    $httpStatus = extractHttpStatus($http_response_header ?? []);

    logInfo('HTTP stream 外部 OTP 接口请求完成', [
        'httpStatus' => $httpStatus,
        'hasResponseBody' => $responseBody !== false && $responseBody !== '',
    ]);

    if ($responseBody === false) {
        $lastError = error_get_last();
        $message = isset($lastError['message']) ? (string) $lastError['message'] : '未知 HTTP stream 错误';
        logInfo('HTTP stream 外部 OTP 接口请求失败', ['error' => $message]);
        return OtpApiResult::fromLocalError($message, $httpStatus);
    }

    logInfo('开始解析外部 OTP 接口 JSON 返回');
    return parseOtpApiResponse($responseBody, $httpStatus);
}

/**
 * 解析外部 OTP 接口返回内容。
 */
function parseOtpApiResponse(string $responseBody, int $httpStatus): OtpApiResult
{
    $data = json_decode($responseBody, true);
    if (!is_array($data)) {
        logInfo('外部 OTP 接口返回不是有效 JSON', ['responseBody' => $responseBody]);
        return OtpApiResult::fromLocalError('外部接口返回不是有效 JSON', $httpStatus);
    }

    logInfo('外部 OTP 接口 JSON 解析成功');
    return OtpApiResult::fromApiResponse($data, $httpStatus);
}

/**
 * 从 HTTP 响应头中提取状态码。
 */
function extractHttpStatus(array $headers): int
{
    logInfo('开始从 HTTP 响应头中提取状态码');

    foreach ($headers as $header) {
        if (preg_match('/^HTTP\/\S+\s+(\d{3})/', (string) $header, $matches) === 1) {
            $status = (int) $matches[1];
            logInfo('已从 HTTP 响应头中提取状态码', ['httpStatus' => $status]);
            return $status;
        }
    }

    logInfo('未从 HTTP 响应头中提取到状态码');
    return 0;
}

$email = trim((string) ($_POST['email'] ?? ''));
$validationError = null;
$result = null;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    logInfo('收到前端查询验证码请求', ['email' => $email]);
    $validationError = validateEmail($email);

    if ($validationError === null) {
        $result = fetchOtpByEmail($email);
    } else {
        logInfo('前端查询验证码请求已因参数校验失败结束', ['message' => $validationError]);
    }
}
?>
<!doctype html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>邮箱验证码查询</title>
    <style>
        :root {
            color-scheme: light;
            --bg: #f4f6f8;
            --panel: #ffffff;
            --text: #17202a;
            --muted: #667085;
            --line: #d8dee6;
            --accent: #1677ff;
            --accent-dark: #0f5fcc;
            --success-bg: #eaf7ef;
            --success: #12733d;
            --error-bg: #fff1f0;
            --error: #b42318;
            --code-bg: #101828;
            --code-text: #f9fafb;
        }

        * {
            box-sizing: border-box;
        }

        body {
            margin: 0;
            min-height: 100vh;
            font-family: Arial, "Microsoft YaHei", sans-serif;
            color: var(--text);
            background: var(--bg);
        }

        .page {
            width: min(720px, calc(100% - 32px));
            margin: 0 auto;
            padding: 64px 0;
        }

        .panel {
            background: var(--panel);
            border: 1px solid var(--line);
            border-radius: 8px;
            padding: 28px;
            box-shadow: 0 14px 40px rgba(16, 24, 40, 0.08);
        }

        h1 {
            margin: 0 0 8px;
            font-size: 26px;
            line-height: 1.25;
        }

        .subtle {
            margin: 0 0 24px;
            color: var(--muted);
            font-size: 14px;
            line-height: 1.7;
        }

        label {
            display: block;
            margin-bottom: 8px;
            font-size: 14px;
            font-weight: 700;
        }

        .form-row {
            display: flex;
            gap: 12px;
        }

        input[type="email"] {
            width: 100%;
            min-height: 44px;
            padding: 10px 12px;
            border: 1px solid var(--line);
            border-radius: 6px;
            font-size: 15px;
            outline: none;
        }

        input[type="email"]:focus {
            border-color: var(--accent);
            box-shadow: 0 0 0 3px rgba(22, 119, 255, 0.12);
        }

        button {
            flex: 0 0 auto;
            min-height: 44px;
            padding: 0 18px;
            border: 0;
            border-radius: 6px;
            color: #fff;
            background: var(--accent);
            font-size: 15px;
            font-weight: 700;
            cursor: pointer;
        }

        button:hover {
            background: var(--accent-dark);
        }

        .message {
            margin-top: 18px;
            padding: 12px 14px;
            border-radius: 6px;
            font-size: 14px;
            line-height: 1.7;
        }

        .message.error {
            color: var(--error);
            background: var(--error-bg);
        }

        .message.success {
            color: var(--success);
            background: var(--success-bg);
        }

        .result {
            margin-top: 22px;
            border-top: 1px solid var(--line);
            padding-top: 22px;
        }

        .code {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            min-width: 160px;
            min-height: 56px;
            padding: 8px 18px;
            margin-bottom: 16px;
            border-radius: 8px;
            color: var(--code-text);
            background: var(--code-bg);
            font-size: 30px;
            font-weight: 800;
            letter-spacing: 4px;
        }

        dl {
            display: grid;
            grid-template-columns: 128px minmax(0, 1fr);
            gap: 10px 14px;
            margin: 0;
            font-size: 14px;
        }

        dt {
            color: var(--muted);
        }

        dd {
            margin: 0;
            overflow-wrap: anywhere;
        }

        pre {
            margin: 16px 0 0;
            padding: 14px;
            overflow: auto;
            border-radius: 6px;
            color: #f9fafb;
            background: #182230;
            font-size: 13px;
            line-height: 1.6;
        }

        @media (max-width: 560px) {
            .page {
                width: min(100% - 24px, 720px);
                padding: 28px 0;
            }

            .panel {
                padding: 20px;
            }

            .form-row {
                flex-direction: column;
            }

            button {
                width: 100%;
            }

            dl {
                grid-template-columns: 1fr;
                gap: 4px;
            }
        }
    </style>
</head>
<body>
<main class="page">
    <section class="panel">
        <h1>邮箱验证码查询</h1>
        <p class="subtle">输入邮箱后，服务端会调用 OTP 接口并展示读取结果。</p>

        <form method="post" action="">
            <label for="email">邮箱</label>
            <div class="form-row">
                <input id="email" name="email" type="email" value="<?= e($email) ?>" placeholder="请输入邮箱" autocomplete="email" required>
                <button type="submit">获取验证码</button>
            </div>
        </form>

        <?php if ($validationError !== null): ?>
            <div class="message error"><?= e($validationError) ?></div>
        <?php endif; ?>

        <?php if ($result instanceof OtpApiResult): ?>
            <div class="result">
                <?php if ($result->ok && $result->code !== null): ?>
                    <div class="code"><?= e($result->code) ?></div>
                    <div class="message success">已读取到验证码</div>
                <?php else: ?>
                    <div class="message error"><?= e($result->message !== '' ? $result->message : '暂未读取到验证码') ?></div>
                <?php endif; ?>

                <dl>
                    <dt>接口状态</dt>
                    <dd><?= e((string) $result->httpStatus) ?></dd>

                    <dt>邮箱</dt>
                    <dd><?= e($result->email !== '' ? $result->email : $email) ?></dd>

                    <dt>读取结果</dt>
                    <dd><?= $result->ok ? '成功' : '失败' ?></dd>

                    <?php if ($result->checked !== null): ?>
                        <dt>检查次数</dt>
                        <dd><?= e((string) $result->checked) ?></dd>
                    <?php endif; ?>

                    <?php if ($result->method !== null): ?>
                        <dt>读取方式</dt>
                        <dd><?= e($result->method) ?></dd>
                    <?php endif; ?>

                    <?php if ($result->subject !== null): ?>
                        <dt>邮件标题</dt>
                        <dd><?= e($result->subject) ?></dd>
                    <?php endif; ?>

                    <?php if ($result->receivedDateTime !== null): ?>
                        <dt>邮件时间</dt>
                        <dd><?= e($result->receivedDateTime) ?></dd>
                    <?php endif; ?>

                    <?php if ($result->error !== null): ?>
                        <dt>错误信息</dt>
                        <dd><?= e($result->error) ?></dd>
                    <?php endif; ?>
                </dl>

                <pre><?= e(json_encode($result->raw, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT)) ?></pre>
            </div>
        <?php endif; ?>
    </section>
</main>
</body>
</html>
