<?php

declare(strict_types=1);

/**
 * 站內 N 幣「寫入／扣回」。
 *
 * 與顯示端 fate_member_read_ncoin() 對應：
 *  - 若 FATE 會員表（members）有 ncoin 欄位 → 直接加減該欄位。
 *  - 另嘗試同步至主站 spa.users.ncoin（依 Email／帳號名稱對應；無對應者略過）。
 *
 * 兩處彼此獨立，任一可用即視為部分成功；實際發放紀錄以 fate_reward_ledger 為準。
 */

require_once __DIR__ . DIRECTORY_SEPARATOR . 'admin_member_auth.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_ncoin_settings.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_member_register.php';
require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_member_account.php';

/**
 * 對會員增減 N 幣（amount 可為負；最終不會低於 0）。
 *
 * @return array{local:bool,spa:bool}
 */
function fate_ncoin_apply_member(PDO $pdo, int $memberId, int $amount, string $username = ''): array
{
    $res = ['local' => false, 'spa' => false];
    if ($memberId <= 0 || $amount === 0 || !fate_admin_member_auth_ready()) {
        return $res;
    }

    fate_member_ensure_ncoin_column($pdo);

    // 1) FATE 會員表 ncoin 欄位
    $cols = fate_member_table_columns($pdo);
    if (isset($cols['ncoin'])) {
        $db = str_replace('`', '``', (string) FATE_MEMBER_DATABASE);
        $tbl = str_replace('`', '``', (string) FATE_MEMBER_TABLE);
        try {
            $sql = sprintf(
                'UPDATE `%s`.`%s` SET `ncoin` = GREATEST(0, CAST(`ncoin` AS SIGNED) + ?) WHERE `id` = ? LIMIT 1',
                $db,
                $tbl
            );
            $st = $pdo->prepare($sql);
            $st->execute([$amount, $memberId]);
            $res['local'] = true;
        } catch (Throwable) {
            $res['local'] = false;
        }
    }

    // 2) 主站 spa.users.ncoin（依 Email／帳號對應）
    $spaQt = fate_member_spa_users_qualified();
    if ($spaQt !== null) {
        $hasNcoin = false;
        try {
            $chk = $pdo->query(sprintf('SHOW COLUMNS FROM %s LIKE \'ncoin\'', $spaQt));
            $hasNcoin = $chk !== false && $chk->fetch(PDO::FETCH_ASSOC) !== false;
        } catch (Throwable) {
            $hasNcoin = false;
        }

        if ($hasNcoin) {
            $email = '';
            $uname = trim($username);
            $fr = fate_public_member_login_row_fetch_by_id($pdo, $memberId);
            if ($fr['found'] && is_array($fr['row'])) {
                $email = isset($fr['row']['email']) ? trim((string) $fr['row']['email']) : '';
                if ($uname === '' && isset($fr['row']['username'])) {
                    $uname = trim((string) $fr['row']['username']);
                }
            }

            $applyWhere = static function (string $whereSql, string $param) use ($pdo, $spaQt, $amount): int {
                try {
                    $sql = sprintf(
                        'UPDATE %s SET `ncoin` = GREATEST(0, CAST(`ncoin` AS SIGNED) + ?) WHERE %s LIMIT 1',
                        $spaQt,
                        $whereSql
                    );
                    $st = $pdo->prepare($sql);
                    $st->execute([$amount, $param]);

                    return $st->rowCount();
                } catch (Throwable) {
                    return 0;
                }
            };

            $done = 0;
            if ($email !== '' && filter_var($email, FILTER_VALIDATE_EMAIL)) {
                $done = $applyWhere('`email` = ?', $email);
            }
            if ($done < 1 && $uname !== '') {
                $done = $applyWhere('`name` = ?', $uname);
                if ($done < 1 && filter_var($uname, FILTER_VALIDATE_EMAIL)) {
                    $done = $applyWhere('`email` = ?', $uname);
                }
            }
            $res['spa'] = $done > 0;
        }
    }

    return $res;
}

/** 便捷：增加。 */
function fate_ncoin_credit_member(PDO $pdo, int $memberId, int $amount, string $username = ''): array
{
    return fate_ncoin_apply_member($pdo, $memberId, max(0, $amount), $username);
}

/** 便捷：扣回（傳入正數）。 */
function fate_ncoin_debit_member(PDO $pdo, int $memberId, int $amount, string $username = ''): array
{
    return fate_ncoin_apply_member($pdo, $memberId, -max(0, $amount), $username);
}

/**
 * 管理員手動發放 N 幣（無中生有）。
 *
 * @return array{ok:bool,error:?string,amount?:int,ledger_id?:int}
 */
function fate_ncoin_admin_grant(
    PDO $pdo,
    int $memberId,
    int $amount,
    string $note = '',
    int $adminId = 0
): array {
    if ($memberId <= 0) {
        return ['ok' => false, 'error' => '無效的會員編號。'];
    }
    if ($amount < 1) {
        return ['ok' => false, 'error' => '發放金額至少為 1 ' . fate_ncoin_display_name() . '。'];
    }
    if ($amount > 9999999) {
        return ['ok' => false, 'error' => '單次發放上限為 ' . fate_ncoin_amount_with_unit(9999999) . '。'];
    }

    require_once __DIR__ . DIRECTORY_SEPARATOR . 'fate_masseur_rewards.php';

    $fr = fate_public_member_login_row_fetch_by_id($pdo, $memberId);
    if (!$fr['found'] || !is_array($fr['row'])) {
        return ['ok' => false, 'error' => '找不到此會員編號。'];
    }
    if ((int) ($fr['row']['_mem_active'] ?? 0) !== 1) {
        return ['ok' => false, 'error' => '此會員帳號目前已停用。'];
    }

    $username = trim((string) ($fr['row']['username'] ?? ''));
    $displayName = trim((string) ($fr['row']['display_name'] ?? ''));
    $memberLabel = $displayName !== '' ? $displayName : ($username !== '' ? $username : '會員 #' . $memberId);

    $note = mb_substr(trim($note), 0, 120);
    $fullNote = '管理員' . ($adminId > 0 ? ' #' . $adminId : '') . ' 手動發放';
    if ($note !== '') {
        $fullNote .= '：' . $note;
    }
    $fullNote = mb_substr($fullNote, 0, 255);

    fate_reward_ledger_ensure_table($pdo);

    try {
        $pdo->beginTransaction();

        // 用 auto-increment ref_id 避免 UNIQUE KEY 衝突：先取最大 ref_id + 1
        $maxSt = $pdo->query(
            "SELECT COALESCE(MAX(`ref_id`), 0) + 1 FROM `fate_reward_ledger` WHERE `action` = 'admin_grant'"
        );
        $nextRefId = $maxSt !== false ? (int) $maxSt->fetchColumn() : 1;
        if ($nextRefId < 1) {
            $nextRefId = 1;
        }

        $st = $pdo->prepare(
            'INSERT INTO `fate_reward_ledger`
             (`member_id`, `action`, `ref_id`, `amount`, `note`, `applied_local`, `applied_spa`)
             VALUES (?, ?, ?, ?, ?, 0, 0)'
        );
        $st->execute([$memberId, 'admin_grant', $nextRefId, $amount, $fullNote]);
        $ledgerId = (int) $pdo->lastInsertId();
        if ($ledgerId <= 0) {
            throw new RuntimeException('建立發放紀錄失敗。');
        }

        $applied = fate_ncoin_credit_member($pdo, $memberId, $amount, $username);
        if (!$applied['local'] && !$applied['spa']) {
            throw new RuntimeException('入帳失敗，請確認會員帳戶狀態。');
        }

        $pdo->prepare(
            'UPDATE `fate_reward_ledger` SET `applied_local` = ?, `applied_spa` = ? WHERE `id` = ?'
        )->execute([
            $applied['local'] ? 1 : 0,
            $applied['spa'] ? 1 : 0,
            $ledgerId,
        ]);

        $pdo->commit();

        return [
            'ok' => true,
            'error' => null,
            'amount' => $amount,
            'ledger_id' => $ledgerId,
            'member_label' => $memberLabel,
        ];
    } catch (Throwable $e) {
        if ($pdo->inTransaction()) {
            $pdo->rollBack();
        }

        return ['ok' => false, 'error' => $e->getMessage()];
    }
}
