import crypto from 'node:crypto';
import { hashPassword, verifyPassword } from './password.js';
import { signAccessToken, signRefreshToken, verifyRefreshToken } from './jwt.js';
export async function authRoutes(app, opts) {
    const { db, jwtSecret } = opts;
    // --- POST /api/auth/login ---
    app.post('/api/auth/login', {
        config: {
            rateLimit: { max: 5, timeWindow: '1 minute' },
        },
        schema: {
            body: {
                type: 'object',
                required: ['username', 'password'],
                properties: {
                    username: { type: 'string', minLength: 1 },
                    password: { type: 'string', minLength: 1 },
                },
            },
        },
    }, async (request, reply) => {
        const { username, password } = request.body;
        const user = db.prepare('SELECT * FROM users WHERE username = ?').get(username);
        if (!user || !(await verifyPassword(password, user.password_hash))) {
            return reply.code(401).send({ error: 'Invalid username or password' });
        }
        // Create session
        const sessionId = crypto.randomUUID();
        const refreshToken = signRefreshToken({ sessionId, userId: user.id }, jwtSecret);
        const tokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex');
        const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();
        db.prepare('INSERT INTO sessions (id, user_id, token_hash, expires_at, created_at) VALUES (?, ?, ?, ?, ?)').run(sessionId, user.id, tokenHash, expiresAt, new Date().toISOString());
        // Update last_login
        db.prepare('UPDATE users SET last_login = ? WHERE id = ?').run(new Date().toISOString(), user.id);
        // Audit log
        db.prepare('INSERT INTO audit_log (user_id, action, details, created_at) VALUES (?, ?, ?, ?)').run(user.id, 'login', JSON.stringify({ ip: request.ip }), new Date().toISOString());
        const accessToken = signAccessToken({ userId: user.id, role: user.role }, jwtSecret);
        const isSecure = request.protocol === 'https';
        reply
            .setCookie('access_token', accessToken, {
            httpOnly: true,
            secure: isSecure,
            sameSite: 'strict',
            path: '/',
            maxAge: 24 * 60 * 60, // 24h
        })
            .setCookie('refresh_token', refreshToken, {
            httpOnly: true,
            secure: isSecure,
            sameSite: 'strict',
            path: '/api/auth/refresh',
            maxAge: 30 * 24 * 60 * 60, // 30d
        });
        return {
            user: {
                id: user.id,
                username: user.username,
                email: user.email,
                role: user.role,
            },
        };
    });
    // --- POST /api/auth/register (admin only) ---
    app.post('/api/auth/register', {
        preHandler: [app.requireAuth, app.requireRole('admin')],
        schema: {
            body: {
                type: 'object',
                required: ['username', 'password'],
                properties: {
                    username: { type: 'string', minLength: 1 },
                    password: { type: 'string', minLength: 6 },
                    email: { type: 'string' },
                    role: { type: 'string', enum: ['admin', 'operator', 'viewer'] },
                },
            },
        },
    }, async (request, reply) => {
        const { username, password, email, role } = request.body;
        const validRoles = ['admin', 'operator', 'viewer'];
        const userRole = role && validRoles.includes(role) ? role : 'operator';
        const existing = db.prepare('SELECT id FROM users WHERE username = ?').get(username);
        if (existing) {
            return reply.code(409).send({ error: 'Username already exists' });
        }
        const id = crypto.randomUUID();
        const passwordHash = await hashPassword(password);
        db.prepare('INSERT INTO users (id, username, email, password_hash, role, created_at) VALUES (?, ?, ?, ?, ?, ?)').run(id, username, email || null, passwordHash, userRole, new Date().toISOString());
        // Audit log
        db.prepare('INSERT INTO audit_log (user_id, action, details, created_at) VALUES (?, ?, ?, ?)').run(request.user.userId, 'create_user', JSON.stringify({ newUserId: id, username, role: userRole }), new Date().toISOString());
        return reply.code(201).send({
            user: { id, username, email: email || null, role: userRole },
        });
    });
    // --- POST /api/auth/refresh ---
    app.post('/api/auth/refresh', async (request, reply) => {
        const refreshToken = request.cookies?.refresh_token;
        if (!refreshToken) {
            return reply.code(401).send({ error: 'Refresh token required' });
        }
        try {
            const payload = verifyRefreshToken(refreshToken, jwtSecret);
            const tokenHash = crypto.createHash('sha256').update(refreshToken).digest('hex');
            const session = db
                .prepare('SELECT * FROM sessions WHERE id = ? AND token_hash = ?')
                .get(payload.sessionId, tokenHash);
            if (!session || new Date(session.expires_at) < new Date()) {
                return reply.code(401).send({ error: 'Invalid or expired session' });
            }
            const user = db.prepare('SELECT * FROM users WHERE id = ?').get(session.user_id);
            if (!user) {
                return reply.code(401).send({ error: 'User not found' });
            }
            const accessToken = signAccessToken({ userId: user.id, role: user.role }, jwtSecret);
            const isSecure = request.protocol === 'https';
            reply.setCookie('access_token', accessToken, {
                httpOnly: true,
                secure: isSecure,
                sameSite: 'strict',
                path: '/',
                maxAge: 24 * 60 * 60,
            });
            return { user: { id: user.id, username: user.username, role: user.role } };
        }
        catch {
            return reply.code(401).send({ error: 'Invalid refresh token' });
        }
    });
    // --- POST /api/auth/logout ---
    app.post('/api/auth/logout', { preHandler: [app.requireAuth] }, async (request, reply) => {
        // Delete all sessions for user
        db.prepare('DELETE FROM sessions WHERE user_id = ?').run(request.user.userId);
        reply
            .clearCookie('access_token', { path: '/' })
            .clearCookie('refresh_token', { path: '/api/auth/refresh' });
        return { ok: true };
    });
    // --- GET /api/auth/me ---
    app.get('/api/auth/me', { preHandler: [app.requireAuth] }, async (request) => {
        const user = db
            .prepare('SELECT id, username, email, role, created_at, last_login FROM users WHERE id = ?')
            .get(request.user.userId);
        if (!user) {
            return { error: 'User not found' };
        }
        return { user };
    });
}
//# sourceMappingURL=auth-routes.js.map