import type { Req, Res, Next } from '../types/http';

const crypto = require('crypto');
const {
  getSessionUser,
  COOKIE_NAME,
  SINGLE_COOKIE_NAME,
  cookieOpts,
  publicUser,
  recordLogin,
} = require('../services/authService.cts');
const { getDb, getSetting } = require('../db/database.cts');
const { standardizeError } = require('./errorFormatter.cts');

function getSingleModeUser(): any {
  if (getSetting('auth_mode') !== 'single') return null;
  const userId = getSetting('default_user_id');
  if (!userId) return null;
  // Single-user mode: validate only that the configured user exists, is active,
  // and has role 'user'. Sessions are not relevant here.
  const row = getDb()
    .prepare(
      `
    SELECT id, username, display_name, role, must_change_password, first_login,
           active, is_default_admin, last_seen_version
    FROM users
    WHERE id = ? AND role = 'user' AND active = 1
  `,
    )
    .get(userId);
  return row ? publicUser(row) : null;
}

function requireAuth(req: Req, res: Res, next: Next): any {
  // Single-user mode: bypass session entirely, auto-attach the default user
  const singleUser = getSingleModeUser();
  if (singleUser) {
    req.user = singleUser;
    req.singleUserMode = true;

    // Track logins via a presence cookie so login history works without a real session.
    const existing = req.cookies?.[SINGLE_COOKIE_NAME];
    if (existing) {
      req.singleSessionId = existing;
    } else {
      const sessionId = crypto.randomUUID();
      res.cookie(SINGLE_COOKIE_NAME, sessionId, {
        httpOnly: true,
        sameSite: 'strict',
        secure: cookieOpts(req).secure,
        maxAge: 30 * 86400 * 1000, // 30 days
        path: '/',
      });
      req.singleSessionId = sessionId;
      // Non-blocking — don't delay the first request
      setImmediate(() => {
        try {
          recordLogin(singleUser.id, req.ip, req.get('user-agent'), sessionId);
        } catch {}
      });
    }

    return next();
  }

  const user = getSessionUser(req.cookies?.[COOKIE_NAME]);
  if (!user) return res.status(401).json(standardizeError('Not authenticated', 'AUTH_ERROR'));
  req.user = user;
  next();
}

function requireUser(req: Req, res: Res, next: Next): any {
  if (req.user?.is_default_admin) {
    return res
      .status(403)
      .json(standardizeError('Default admin account does not have tracker access', 'FORBIDDEN'));
  }
  if (!['user', 'admin'].includes(req.user?.role)) {
    return res
      .status(403)
      .json(standardizeError('Access denied: user account required', 'FORBIDDEN'));
  }
  next();
}

function requireAdmin(req: Req, res: Res, next: Next): any {
  // In single-user mode the auto-attached user is never admin,
  // so admin routes naturally stay protected by session.
  if (req.user?.role !== 'admin') {
    return res
      .status(403)
      .json(standardizeError('Access denied: admin account required', 'FORBIDDEN'));
  }
  next();
}

module.exports = { requireAuth, requireUser, requireAdmin };
