import { Hono } from 'hono';
import { randomUUID } from 'crypto';
import { query, withTransaction } from '../db.js';
import { sessionAuth } from '../middleware/session.js';
import { hashKey } from '../keys.js';
import { signBalance } from '../balance-integrity.js';
import { getSpendingPeriodStart, getSpendingPeriodEnd } from '../spending.js';
const users = new Hono();
// All routes require session auth
users.use('/*', sessionAuth);
// GET /v1/users/me
users.get('/me', async (c) => {
    const userId = c.get('userId');
    const userResult = query('SELECT * FROM users WHERE id = ?', [userId]);
    if (userResult.rows.length === 0) {
        return c.json({ error: 'User not found' }, 404);
    }
    const user = userResult.rows[0];
    const keyResult = query(`SELECT id, key_prefix, balance_cents, status, created_at
     FROM license_keys WHERE user_id = ? AND status = 'active'`, [userId]);
    return c.json({
        id: user.id,
        email: user.email,
        stripe_customer_id: user.stripe_customer_id,
        created_at: user.created_at,
        license_key: keyResult.rows[0]
            ? {
                id: keyResult.rows[0].id,
                prefix: keyResult.rows[0].key_prefix,
                balance_cents: keyResult.rows[0].balance_cents,
                files_remaining: Math.floor(keyResult.rows[0].balance_cents / 3),
                status: keyResult.rows[0].status,
                created_at: keyResult.rows[0].created_at,
            }
            : null,
    });
});
// POST /v1/users/me/regenerate-key
users.post('/me/regenerate-key', async (c) => {
    const userId = c.get('userId');
    const rawKey = `lk_${randomUUID().replace(/-/g, '')}`;
    const hash = hashKey(rawKey);
    const prefix = rawKey.slice(0, 8);
    const keyId = randomUUID();
    const transferredBalance = withTransaction(() => {
        // Sum balance and capture spending settings from all active keys before revoking
        const oldKeys = query(`SELECT balance_cents, spending_limit_cents, spending_limit_reset_at FROM license_keys WHERE user_id = ? AND status = 'active'`, [userId]);
        const totalBalance = oldKeys.rows.reduce((sum, k) => sum + k.balance_cents, 0);
        // Take spending limit settings from the first active key (if any)
        const spendingLimitCents = oldKeys.rows.length > 0 ? oldKeys.rows[0].spending_limit_cents : null;
        const spendingLimitResetAt = oldKeys.rows.length > 0 ? oldKeys.rows[0].spending_limit_reset_at : null;
        // Revoke existing active keys
        query(`UPDATE license_keys SET status = 'revoked' WHERE user_id = ? AND status = 'active'`, [userId]);
        // Generate new key with transferred balance and spending settings
        const transferHmac = signBalance(keyId, totalBalance);
        query('INSERT INTO license_keys (id, user_id, key_hash, key_prefix, balance_cents, spending_limit_cents, spending_limit_reset_at, balance_hmac) VALUES (?, ?, ?, ?, ?, ?, ?, ?)', [keyId, userId, hash, prefix, totalBalance, spendingLimitCents, spendingLimitResetAt, transferHmac]);
        return totalBalance;
    });
    return c.json({
        license_key: rawKey,
        prefix,
        balance_cents: transferredBalance,
        message: 'New key generated. Previous keys have been revoked. Balance and spending settings transferred. Store this key securely — it cannot be shown again.',
    });
});
// GET /v1/users/me/charges?page=1&limit=20
users.get('/me/charges', async (c) => {
    const userId = c.get('userId');
    const page = Math.max(1, parseInt(c.req.query('page') ?? '1', 10) || 1);
    const limit = Math.min(100, Math.max(1, parseInt(c.req.query('limit') ?? '20', 10) || 20));
    const offset = (page - 1) * limit;
    const keyResult = query(`SELECT id FROM license_keys WHERE user_id = ? AND status = 'active'`, [userId]);
    if (keyResult.rows.length === 0) {
        return c.json({ charges: [], page, limit, total: 0, total_pages: 0 });
    }
    const keyId = keyResult.rows[0].id;
    const countResult = query('SELECT COUNT(*) as c FROM charges WHERE license_key_id = ?', [keyId]);
    const total = countResult.rows[0].c;
    const chargesResult = query('SELECT id, amount_cents, document_hash, status, file_type, file_size_bytes, processing_ms, created_at FROM charges WHERE license_key_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?', [keyId, limit, offset]);
    return c.json({
        charges: chargesResult.rows,
        page,
        limit,
        total,
        total_pages: Math.ceil(total / limit),
    });
});
// GET /v1/users/me/payments?page=1&limit=20
users.get('/me/payments', async (c) => {
    const userId = c.get('userId');
    const page = Math.max(1, parseInt(c.req.query('page') ?? '1', 10) || 1);
    const limit = Math.min(100, Math.max(1, parseInt(c.req.query('limit') ?? '20', 10) || 20));
    const offset = (page - 1) * limit;
    const countResult = query('SELECT COUNT(*) as c FROM payments WHERE user_id = ?', [userId]);
    const total = countResult.rows[0].c;
    const paymentsResult = query('SELECT id, amount_cents, stripe_payment_intent_id, created_at FROM payments WHERE user_id = ? ORDER BY created_at DESC LIMIT ? OFFSET ?', [userId, limit, offset]);
    return c.json({
        payments: paymentsResult.rows,
        page,
        limit,
        total,
        total_pages: Math.ceil(total / limit),
    });
});
// PUT /v1/users/me/spending-limit
users.put('/me/spending-limit', async (c) => {
    const userId = c.get('userId');
    const body = await c.req.json();
    const limitCents = body.limit_cents;
    // Validation: must be null, 0, or positive integer
    if (limitCents !== null && limitCents !== undefined) {
        if (!Number.isInteger(limitCents) || limitCents < 0) {
            return c.json({ error: 'limit_cents must be null, 0, or a positive integer' }, 400);
        }
        if (limitCents > 0 && limitCents < 100) {
            return c.json({ error: 'Minimum non-zero spending limit is 100 ($1.00)' }, 400);
        }
        if (limitCents > 100000) {
            return c.json({ error: 'Maximum spending limit is 100000 ($1,000.00)' }, 400);
        }
    }
    const keyResult = query(`SELECT id FROM license_keys WHERE user_id = ? AND status = 'active'`, [userId]);
    if (keyResult.rows.length === 0) {
        return c.json({ error: 'No active license key found' }, 404);
    }
    const keyId = keyResult.rows[0].id;
    const newLimit = limitCents === undefined ? null : limitCents;
    query('UPDATE license_keys SET spending_limit_cents = ? WHERE id = ?', [newLimit, keyId]);
    // Return current spending data
    const periodStart = getSpendingPeriodStart(null);
    const spentResult = query(`SELECT COALESCE(SUM(amount_cents), 0) as total
     FROM charges
     WHERE license_key_id = ? AND status IN ('pending', 'confirmed') AND created_at >= ?`, [keyId, periodStart]);
    return c.json({
        spending_limit_cents: newLimit,
        spent_this_month_cents: spentResult.rows[0].total,
        resets_at: getSpendingPeriodEnd(periodStart),
    });
});
// POST /v1/users/me/spending-limit/reset
users.post('/me/spending-limit/reset', async (c) => {
    const userId = c.get('userId');
    const keyResult = query(`SELECT id, spending_limit_cents FROM license_keys WHERE user_id = ? AND status = 'active'`, [userId]);
    if (keyResult.rows.length === 0) {
        return c.json({ error: 'No active license key found' }, 404);
    }
    const key = keyResult.rows[0];
    if (key.spending_limit_cents === null) {
        return c.json({ error: 'No spending limit is set. Nothing to reset.' }, 400);
    }
    const now = new Date().toISOString().replace('T', ' ').replace(/\.\d{3}Z$/, '');
    query('UPDATE license_keys SET spending_limit_reset_at = ? WHERE id = ?', [now, key.id]);
    return c.json({
        spending_limit_cents: key.spending_limit_cents,
        spent_this_month_cents: 0,
        reset_at: now,
        resets_at: getSpendingPeriodEnd(now),
    });
});
export default users;
//# sourceMappingURL=users.js.map