<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;

function Mirai_expGet($uid = 0) {
    if (!$uid) {
        $user = Mirai_user();
        if (!$user->hasLogin()) return 0;
        $uid = $user->uid;
    }
    $db = \Typecho\Db::get();
    $row = $db->fetchRow($db->select('exp')->from('table.users')->where('uid = ?', $uid));
    return (int)($row['exp'] ?? 0);
}

function Mirai_expIsAllowAdd($uid) {
    $options = Mirai_opt();
    $dailyLimit = isset($options->expDailyLimit) ? (int)$options->expDailyLimit : 100;
    if ($dailyLimit <= 0) return true;

    $db = \Typecho\Db::get();
    $dailyTable = Mirai_pointsTable('mirai_points_daily');
    $today = date('Y-m-d');
    $row = $db->fetchRow($db->select('exp_free')->from($dailyTable)->where('uid = ? AND date = ?', $uid, $today));
    $todayFree = (int)($row['exp_free'] ?? 0);

    return $todayFree < $dailyLimit;
}

function Mirai_expCheckDedup($uid, $targetType, $targetId, $action, $maxCount = 0) {
    return Mirai_pointsCheckDedup($uid, $targetType, $targetId, 'exp_' . $action, $maxCount);
}

function Mirai_expAdd($uid, $amount, $action, $refType = null, $refId = null, $remark = '', $maxCount = 0) {
    if (!$uid || $amount <= 0) return ['success' => false, 'msg' => '参数无效'];
    if (!Mirai_levelEnabled()) return ['success' => false, 'msg' => '等级功能未启用'];
    if (!Mirai_expIsAllowAdd($uid)) return ['success' => false, 'msg' => '今日经验值已达上限'];

    if ($refType !== null || $refId !== null) {
        $dedup = Mirai_expCheckDedup($uid, $refType ?: '', $refId ?: 0, $action, $maxCount);
        if (!$dedup['allowed']) {
            return ['success' => false, 'msg' => '已获取过该经验值'];
        }
    }

    $db = \Typecho\Db::get();
    $lockKey = 'mirai_exp_' . $uid;
    $locked = false;
    if (function_exists('Mirai_payAcquireLock')) {
        $locked = Mirai_payAcquireLock($lockKey);
    }

    try {
        $row = $db->fetchRow($db->select('exp', 'level')->from('table.users')->where('uid = ?', $uid));
        $expBefore = (int)($row['exp'] ?? 0);
        $levelBefore = (int)($row['level'] ?? 1);
        $expAfter = $expBefore + $amount;

        $db->query($db->update('table.users')->rows([
            'exp' => $expAfter,
            'exp_updated' => time(),
        ])->where('uid = ?', $uid));

        $upgradeResult = Mirai_levelCheckUpgrade($uid);
        $finalLevel = $upgradeResult['upgraded'] ? $upgradeResult['level_after'] : $levelBefore;

        $expLogTable = Mirai_pointsTable('mirai_exp_logs');
        $db->query($db->insert($expLogTable)->rows([
            'uid' => $uid,
            'action' => $action,
            'amount' => $amount,
            'exp_before' => $expBefore,
            'exp_after' => $expAfter,
            'level_before' => $levelBefore,
            'level_after' => $finalLevel,
            'ref_type' => $refType,
            'ref_id' => $refId,
            'remark' => $remark,
            'created' => time(),
        ]));

        $dailyTable = Mirai_pointsTable('mirai_points_daily');
        $today = date('Y-m-d');
        $now = time();
        $dailyRow = $db->fetchRow($db->select()->from($dailyTable)->where('uid = ? AND date = ?', $uid, $today));
        if ($dailyRow) {
            $db->query($db->update($dailyTable)->rows([
                'exp_free' => (int)$dailyRow['exp_free'] + $amount,
                'exp_total' => (int)$dailyRow['exp_total'] + $amount,
                'updated' => $now,
            ])->where('id = ?', $dailyRow['id']));
        } else {
            $db->query($db->insert($dailyTable)->rows([
                'uid' => $uid,
                'date' => $today,
                'points_free' => 0,
                'points_total' => 0,
                'points_spent' => 0,
                'exp_free' => $amount,
                'exp_total' => $amount,
                'created' => $now,
                'updated' => $now,
            ]));
        }

        if ($locked && function_exists('Mirai_payReleaseLock')) Mirai_payReleaseLock($lockKey);

        return [
            'success' => true,
            'exp_before' => $expBefore,
            'exp_after' => $expAfter,
            'amount' => $amount,
            'upgraded' => $upgradeResult['upgraded'],
            'level_before' => $upgradeResult['level_before'] ?? $levelBefore,
            'level_after' => $upgradeResult['level_after'] ?? $levelBefore,
        ];
    } catch (\Exception $e) {
        if ($locked && function_exists('Mirai_payReleaseLock')) Mirai_payReleaseLock($lockKey);
        return ['success' => false, 'msg' => $e->getMessage()];
    }
}

function Mirai_expGetLogs($uid, $page = 1, $pageSize = 20) {
    $db = \Typecho\Db::get();
    $expLogTable = Mirai_pointsTable('mirai_exp_logs');
    $offset = ($page - 1) * $pageSize;

    $count = $db->fetchRow($db->select(['COUNT(*)' => 'cnt'])->from($expLogTable)->where('uid = ?', $uid));
    $total = (int)($count['cnt'] ?? 0);

    $rows = $db->fetchAll($db->select()->from($expLogTable)
        ->where('uid = ?', $uid)
        ->order('created', \Typecho\Db::SORT_DESC)
        ->limit($pageSize)
        ->offset($offset));

    return ['list' => $rows, 'total' => $total, 'page' => $page, 'pageSize' => $pageSize];
}

function Mirai_expGetTaskValue($taskKey) {
    $options = Mirai_opt();
    $field = 'expTask_' . $taskKey;
    return isset($options->$field) ? (int)$options->$field : 0;
}