import { SignJWT, jwtVerify } from 'jose';
import { userDb, appConfigDb } from '../modules/database/index.js';
import { IS_PLATFORM, PLATFORM_SHARED_SECRET } from '../constants/config.js';
// Use env var if set, otherwise auto-generate a unique secret per installation
const JWT_SECRET = process.env.JWT_SECRET || appConfigDb.getOrCreateJwtSecret();
// Optional API key middleware
const validateApiKey = (req, res, next) => {
    // Skip API key validation if not configured
    if (!process.env.API_KEY) {
        return next();
    }
    const apiKey = req.headers['x-api-key'];
    if (apiKey !== process.env.API_KEY) {
        return res.status(401).json({ error: 'Invalid API key' });
    }
    next();
};
/**
 * Validates the platform shared secret from a request.
 * Returns null on success, or an error message string on failure.
 *
 * Note: When IS_PLATFORM=true, config.js fatally exits at startup if
 * PLATFORM_SHARED_SECRET is unset, so this function without a secret
 * only applies in OSS mode where platform auth is not active.
 */
function validatePlatformSecret(reqOrSecret) {
    if (!PLATFORM_SHARED_SECRET) {
        return null; // OSS mode — no platform secret expected
    }
    const provided = typeof reqOrSecret === 'string'
        ? reqOrSecret
        : reqOrSecret?.headers?.['x-platform-shared-secret'];
    if (!provided || provided !== PLATFORM_SHARED_SECRET) {
        return 'Invalid or missing platform shared secret';
    }
    return null;
}
// JWT authentication middleware
const authenticateToken = async (req, res, next) => {
    // Platform mode: validate shared secret, then use single database user
    if (IS_PLATFORM) {
        const secretErr = validatePlatformSecret(req);
        if (secretErr) {
            return res.status(403).json({ error: secretErr });
        }
        try {
            const user = userDb.getFirstUser();
            if (!user) {
                return res.status(500).json({ error: 'Platform mode: No user found in database' });
            }
            req.user = user;
            return next();
        }
        catch (error) {
            console.error('Platform mode error:', error);
            return res.status(500).json({ error: 'Platform mode: Failed to fetch user' });
        }
    }
    // Normal OSS JWT validation
    const authHeader = req.headers['authorization'];
    let token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
    // Also check query param for SSE endpoints (EventSource can't set headers)
    if (!token && req.query.token) {
        token = req.query.token;
    }
    if (!token) {
        return res.status(401).json({ error: 'Access denied. No token provided.' });
    }
    try {
        const secret = new TextEncoder().encode(JWT_SECRET);
        const { payload: decoded } = await jwtVerify(token, secret);
        // Verify user still exists and is active
        const user = userDb.getUserById(decoded.userId);
        if (!user) {
            return res.status(401).json({ error: 'Invalid token. User not found.' });
        }
        // Auto-refresh: if token is past halfway through its lifetime, issue a new one
        if (decoded.exp && decoded.iat) {
            const now = Math.floor(Date.now() / 1000);
            const halfLife = (decoded.exp - decoded.iat) / 2;
            if (now > decoded.iat + halfLife) {
                const newToken = generateToken(user);
                res.setHeader('X-Refreshed-Token', newToken);
            }
        }
        req.user = user;
        next();
    }
    catch (error) {
        console.error('Token verification error:', error);
        return res.status(403).json({ error: 'Invalid token' });
    }
};
// Generate JWT token
const generateToken = (user) => {
    return new SignJWT({ userId: user.id, username: user.username })
        .setProtectedHeader({ alg: 'HS256' })
        .setIssuedAt()
        .setExpirationTime('7d')
        .sign(new TextEncoder().encode(JWT_SECRET));
};
// WebSocket authentication function
const authenticateWebSocket = async (token, sharedSecret) => {
    // Platform mode: validate shared secret, then return first user
    if (IS_PLATFORM) {
        const secretErr = validatePlatformSecret(sharedSecret || '');
        if (secretErr) {
            return null;
        }
        try {
            const user = userDb.getFirstUser();
            if (user) {
                return { id: user.id, userId: user.id, username: user.username };
            }
            return null;
        }
        catch (error) {
            console.error('Platform mode WebSocket error:', error);
            return null;
        }
    }
    // Normal OSS JWT validation
    if (!token) {
        return null;
    }
    try {
        const secret = new TextEncoder().encode(JWT_SECRET);
        const { payload: decoded } = await jwtVerify(token, secret);
        // Verify user actually exists in database (matches REST authenticateToken behavior)
        const user = userDb.getUserById(decoded.userId);
        if (!user) {
            return null;
        }
        return { userId: user.id, username: user.username };
    }
    catch (error) {
        console.error('WebSocket token verification error:', error);
        return null;
    }
};
export { validateApiKey, authenticateToken, generateToken, authenticateWebSocket, JWT_SECRET };
//# sourceMappingURL=auth.js.map