import { Hono } from 'hono';
import { randomUUID } from 'crypto';
import { query } from '../db.js';
import { getEnv } from '../env.js';
import { signToken, verifyToken, hashKey } from '../keys.js';
import { getPublicBaseUrl } from '../public-url.js';
const auth = new Hono();
/**
 * Core magic link logic — shared by API route and dashboard pages.
 * Upserts user, generates token, sends email (or returns dev_token).
 *
 * @param email - User email
 * @param publicBaseUrl - Public-facing base URL for the magic link (detected from request headers).
 *                        Falls back to env.DASHBOARD_URL if not provided.
 */
export async function sendMagicLink(email, publicBaseUrl) {
    const env = getEnv();
    // Upsert user
    const userId = randomUUID();
    query(`INSERT INTO users (id, email) VALUES (?, ?)
     ON CONFLICT (email) DO UPDATE SET email = EXCLUDED.email`, [userId, email]);
    // Get the actual user (may be existing)
    const userResult = query('SELECT id, email FROM users WHERE email = ?', [email]);
    const user = userResult.rows[0];
    // Generate magic link token (10 minute expiry)
    const token = signToken({ userId: user.id, email: user.email }, env.SESSION_SECRET, 10 * 60 * 1000);
    // Use detected public URL for the magic link (cloud proxies, RunPod, etc.)
    const baseUrl = publicBaseUrl || env.DASHBOARD_URL;
    // If Resend API key is configured, send email
    if (env.RESEND_API_KEY) {
        const link = `${baseUrl}/auth/verify?token=${encodeURIComponent(token)}`;
        const emailRes = await fetch('https://api.resend.com/emails', {
            method: 'POST',
            headers: {
                'Content-Type': 'application/json',
                Authorization: `Bearer ${env.RESEND_API_KEY}`,
            },
            body: JSON.stringify({
                from: env.FROM_EMAIL,
                to: email,
                subject: 'Your login link - OCR Provenance',
                html: `<p>Click <a href="${link}">here</a> to sign in. This link expires in 10 minutes.</p>`,
            }),
        });
        if (!emailRes.ok) {
            console.error(`[Auth] Failed to send email: ${emailRes.status} ${await emailRes.text()}`);
            return { sent: false, error: 'Failed to send magic link email' };
        }
        return { sent: true };
    }
    // Dev mode: return token directly — ONLY safe on localhost.
    // On cloud deployments (RunPod, Vast.ai) with public proxy URLs,
    // returning the token bypasses email verification and allows anyone
    // to authenticate as any email. The publicBaseUrl check ensures
    // dev tokens are only returned when accessed via localhost.
    const isLocalhost = !publicBaseUrl ||
        publicBaseUrl.includes('localhost') ||
        publicBaseUrl.includes('127.0.0.1');
    if (isLocalhost) {
        return { sent: true, dev_token: token };
    }
    // Cloud environment without email sending configured — refuse login
    // to prevent authentication bypass
    console.error(`[Auth] RESEND_API_KEY not configured and request is from non-localhost origin (${publicBaseUrl}). ` +
        `Cannot send magic link. Configure RESEND_API_KEY for cloud deployments.`);
    return { sent: false, error: 'Email sending is not configured. Contact the administrator to set up RESEND_API_KEY.' };
}
// POST /v1/auth/send-link
auth.post('/send-link', async (c) => {
    const body = await c.req.json();
    if (!body.email || typeof body.email !== 'string') {
        return c.json({ error: 'Email is required' }, 400);
    }
    const email = body.email.toLowerCase().trim();
    const result = await sendMagicLink(email, getPublicBaseUrl(c));
    if (result.error) {
        return c.json({ error: result.error }, 500);
    }
    return c.json({ sent: result.sent, ...(result.dev_token ? { dev_token: result.dev_token } : {}) });
});
// POST /v1/auth/verify
auth.post('/verify', async (c) => {
    const body = await c.req.json();
    if (!body.token || typeof body.token !== 'string') {
        return c.json({ error: 'Token is required' }, 400);
    }
    const env = getEnv();
    const payload = verifyToken(body.token, env.SESSION_SECRET);
    if (!payload) {
        return c.json({ error: 'Invalid or expired token' }, 401);
    }
    // Verify user exists
    const userResult = query('SELECT id, email FROM users WHERE id = ?', [payload.userId]);
    if (userResult.rows.length === 0) {
        return c.json({ error: 'User not found' }, 404);
    }
    const user = userResult.rows[0];
    // Ensure user has a license key
    const existingKey = query(`SELECT id FROM license_keys WHERE user_id = ? AND status = 'active'`, [user.id]);
    if (existingKey.rows.length === 0) {
        const rawKey = `lk_${randomUUID().replace(/-/g, '')}`;
        const hash = hashKey(rawKey);
        const prefix = rawKey.slice(0, 8);
        query('INSERT INTO license_keys (id, user_id, key_hash, key_prefix) VALUES (?, ?, ?, ?)', [randomUUID(), user.id, hash, prefix]);
    }
    // Create session (30-day expiry)
    const sessionToken = randomUUID();
    query(`INSERT INTO sessions (token, user_id, expires_at)
     VALUES (?, ?, datetime('now', '+30 days'))`, [sessionToken, user.id]);
    return c.json({
        session_token: sessionToken,
        user: { id: user.id, email: user.email },
    });
});
export default auth;
//# sourceMappingURL=auth.js.map