<?php
/**
 * 芋头CMS
 * ============================================================================
 * 版权所有 2016-2028 沅陵县乌托邦网络服务有限公司，并保留所有权利。
 * 网站地址: http://www.yutoucms.cn
 * ----------------------------------------------------------------------------
 * 如果商业用途务必到官方购买正版授权, 以免引起不必要的法律纠纷.
 * ============================================================================
 * Author: 芋头 <mxgsf@qq.com>
 * Date: 2026-5-20
 */

header('Content-Type: application/json; charset=utf-8');
header('X-Content-Type-Options: nosniff');
header('Cache-Control: no-store');

$requestOrigin = trim((string) ($_SERVER['HTTP_ORIGIN'] ?? ''));
if ($requestOrigin !== '') {
    $originHost = strtolower((string) parse_url($requestOrigin, PHP_URL_HOST));
    $requestHost = strtolower((string) preg_replace('/:\d+$/', '', $_SERVER['HTTP_HOST'] ?? ''));
    if ($originHost === '' || $originHost !== $requestHost) {
        http_response_code(403);
        exit(json_encode(['code' => 403, 'msg' => '跨域请求已拒绝'], JSON_UNESCAPED_UNICODE));
    }
}

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit(json_encode(['code' => 405, 'msg' => '仅支持 POST 请求'], JSON_UNESCAPED_UNICODE));
}

require_once dirname(__DIR__) . '/core/lib/session.php';
cmsStartSession();
require_once dirname(__DIR__) . '/core/db/db.php';
require_once dirname(__DIR__) . '/core/lib/common.php';
require_once dirname(__DIR__) . '/core/lib/login_security.php';

$db = \Core\Db\DB::getInstance();
$action = trim((string) ($_POST['action'] ?? $_GET['action'] ?? ''));
$redirect = cmsMemberRedirect($_POST['redirect'] ?? $_GET['redirect'] ?? '/member/index.php');

try {
    switch ($action) {
        case 'send_code':
            cmsHandleSendCode();
            break;

        case 'register':
            cmsHandleRegister($db, $redirect);
            break;

        case 'login':
            cmsHandleLogin($db, $redirect);
            break;

        case 'logout':
            cmsHandleLogout($redirect);
            break;

        default:
            cmsMemberJson(404, '未知操作');
    }
} catch (Exception $e) {
    cmsMemberJson(500, '系统错误，请稍后再试');
}

function cmsHandleSendCode()
{
    $mobile = trim((string) ($_POST['mobile'] ?? $_GET['mobile'] ?? ''));
    if (!preg_match('/^1[3-9]\d{9}$/', $mobile)) {
        cmsMemberJson(400, '请输入正确的手机号');
    }

    if (!cmsIsDebugLikeEnv()) {
        cmsMemberJson(503, '短信服务尚未配置，请联系网站管理员');
    }

    $lastSentAt = intval($_SESSION['member_sms_sent_at'] ?? 0);
    if ($lastSentAt > 0 && (time() - $lastSentAt) < 60) {
        cmsMemberJson(429, '验证码发送过于频繁，请稍后再试');
    }

    $code = str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
    $_SESSION['member_sms_mobile'] = $mobile;
    $_SESSION['member_sms_code'] = $code;
    $_SESSION['member_sms_sent_at'] = time();
    $_SESSION['member_sms_expire_at'] = time() + 600;

    cmsMemberJson(200, '本地调试验证码已生成', ['data' => ['code' => $code]]);
}

function cmsHandleRegister($db, $redirect)
{
    $username = trim((string) ($_POST['username'] ?? ''));
    $mobile = trim((string) ($_POST['mobile'] ?? ''));
    $code = trim((string) ($_POST['code'] ?? ''));
    $password = trim((string) ($_POST['password'] ?? ''));
    $passwordConfirm = trim((string) ($_POST['password_confirm'] ?? ''));
    $agree = trim((string) ($_POST['agree'] ?? ''));

    if ($agree !== '1') {
        cmsMemberJson(400, '请先同意用户协议');
    }
    if ($username === '' || $mobile === '' || $code === '' || $password === '' || $passwordConfirm === '') {
        cmsMemberJson(400, '请完整填写注册信息');
    }
    if (strlen($username) < 3 || strlen($username) > 20) {
        cmsMemberJson(400, '用户名长度需在3-20位之间');
    }
    if (!preg_match('/^[a-zA-Z0-9_\x{4e00}-\x{9fa5}]+$/u', $username)) {
        cmsMemberJson(400, '用户名格式不正确');
    }
    if (!preg_match('/^1[3-9]\d{9}$/', $mobile)) {
        cmsMemberJson(400, '请输入正确的手机号');
    }
    if (strlen($password) < 6 || strlen($password) > 20) {
        cmsMemberJson(400, '密码长度需在6-20位之间');
    }
    if ($password !== $passwordConfirm) {
        cmsMemberJson(400, '两次输入的密码不一致');
    }
    if (($code !== (string) ($_SESSION['member_sms_code'] ?? '')) || $mobile !== (string) ($_SESSION['member_sms_mobile'] ?? '')) {
        cmsMemberJson(400, '短信验证码错误');
    }
    if (time() > intval($_SESSION['member_sms_expire_at'] ?? 0)) {
        cmsMemberJson(400, '短信验证码已过期');
    }

    $existsByUsername = $db->fetch(
        "SELECT id FROM {$db->table('member')} WHERE username = ? LIMIT 1",
        [$username]
    );
    if ($existsByUsername) {
        cmsMemberJson(400, '用户名已被注册');
    }

    $existsByPhone = $db->fetch(
        "SELECT id FROM {$db->table('member')} WHERE phone = ? LIMIT 1",
        [$mobile]
    );
    if ($existsByPhone) {
        cmsMemberJson(400, '手机号已被注册');
    }

    $defaultGroup = $db->fetch("SELECT id FROM {$db->table('member_group')} WHERE is_default = 1 ORDER BY id ASC LIMIT 1");
    $groupId = intval($defaultGroup['id'] ?? 1);
    if ($groupId <= 0) {
        $groupId = 1;
    }

    $memberId = $db->insert('member', [
        'username' => $username,
        'password' => password_hash($password, PASSWORD_DEFAULT),
        'nickname' => $username,
        'phone' => $mobile,
        'group_id' => $groupId,
        'reg_ip' => cmsMemberClientIp(),
        'reg_time' => time(),
        'update_time' => time(),
        'is_enabled' => 1
    ]);

    session_regenerate_id(true);
    $_SESSION['member_id'] = intval($memberId);
    $_SESSION['member_name'] = $username;
    $_SESSION['member_nickname'] = $username;
    $_SESSION['member_group_id'] = $groupId;

    unset($_SESSION['member_sms_mobile'], $_SESSION['member_sms_code'], $_SESSION['member_sms_sent_at'], $_SESSION['member_sms_expire_at']);

    cmsMemberJson(200, '注册成功', [
        'data' => [
            'redirect' => $redirect,
            'member_id' => intval($memberId)
        ]
    ]);
}

function cmsHandleLogin($db, $redirect)
{
    $username = trim((string) ($_POST['username'] ?? ''));
    $password = trim((string) ($_POST['password'] ?? ''));
    $clientIp = cmsLoginClientIp();
    $securityDir = dirname(__DIR__) . '/data/cache/member-login-security';
    $loginLock = cmsGetLoginLock($username, $clientIp, $securityDir);

    if ($loginLock['locked']) {
        cmsMemberJson(429, '登录尝试过于频繁，请稍后重试');
    }

    if ($username === '' || $password === '') {
        cmsMemberJson(400, '请输入用户名和密码');
    }

    cmsRecordLoginFailure($username, $clientIp, $securityDir);
    $field = preg_match('/^1[3-9]\d{9}$/', $username) ? 'phone' : 'username';
    $member = $db->fetch(
        "SELECT * FROM {$db->table('member')} WHERE {$field} = ? AND is_enabled = 1 LIMIT 1",
        [$username]
    );

    if (!$member) {
        cmsMemberJson(400, '用户不存在或已被禁用');
    }

    $storedPassword = (string) ($member['password'] ?? '');
    $verified = password_verify($password, $storedPassword);
    $legacyMd5Matched = !$verified && md5($password) === $storedPassword;
    if ($legacyMd5Matched) {
        $verified = true;
        $db->update('member', [
            'password' => password_hash($password, PASSWORD_DEFAULT),
            'update_time' => time()
        ], 'id = ?', [intval($member['id'])]);
    }
    if (!$verified) {
        cmsMemberJson(400, '密码错误');
    }

    cmsClearLoginFailures($username, $clientIp, $securityDir);
    session_regenerate_id(true);
    $_SESSION['member_id'] = intval($member['id']);
    $_SESSION['member_name'] = $member['username'];
    $_SESSION['member_nickname'] = $member['nickname'];
    $_SESSION['member_group_id'] = intval($member['group_id'] ?? 0);

    $db->update('member', [
        'last_login_time' => time(),
        'last_login_ip' => cmsMemberClientIp(),
        'update_time' => time()
    ], 'id = ?', [intval($member['id'])]);

    cmsMemberJson(200, '登录成功', [
        'data' => [
            'redirect' => $redirect,
            'member_id' => intval($member['id'])
        ]
    ]);
}

function cmsHandleLogout($redirect)
{
    unset($_SESSION['member_id'], $_SESSION['member_name'], $_SESSION['member_nickname'], $_SESSION['member_group_id']);
    session_regenerate_id(true);
    cmsMemberJson(200, '退出成功', ['data' => ['redirect' => $redirect]]);
}

function cmsMemberRedirect($redirect)
{
    $redirect = trim((string) $redirect);
    if ($redirect === '') {
        return '/member/index.php';
    }

    if (preg_match('#^(https?:)?//#i', $redirect)) {
        return '/member/index.php';
    }

    if ($redirect[0] !== '/') {
        $redirect = '/' . ltrim($redirect, '/');
    }

    return $redirect;
}

function cmsMemberClientIp()
{
    if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
        $parts = explode(',', (string) $_SERVER['HTTP_X_FORWARDED_FOR']);
        return trim($parts[0]);
    }
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
        return trim((string) $_SERVER['HTTP_CLIENT_IP']);
    }
    return trim((string) ($_SERVER['REMOTE_ADDR'] ?? '0.0.0.0'));
}

function cmsIsDebugLikeEnv()
{
    return cmsIsLocalDebugRequest();
}

function cmsMemberJson($code, $msg, $extra = [])
{
    $payload = array_merge([
        'code' => intval($code),
        'msg' => (string) $msg
    ], $extra);

    echo json_encode($payload, JSON_UNESCAPED_UNICODE);
    exit;
}
