// Authentication middleware

import { authConfig } from '../config/auth.js';

/**
 * Require authentication for a route
 * Sets req.user if authenticated, returns 401 if not
 */
export function requireAuth(req, res, next) {
  console.log(`[requireAuth] ${req.method} ${req.path} - session ID: ${req.session?.id || 'NONE'}, has user: ${!!req.session?.user}`);

  // Skip auth if disabled
  if (!authConfig.app.authEnabled) {
    req.user = { id: 'anonymous', email: 'anonymous@local', groups: ['agent-admin'] };
    return next();
  }

  // Check session
  if (!req.session || !req.session.user) {
    console.log(`[requireAuth] Unauthorized - no session or user`);
    return res.status(401).json({
      error: 'Unauthorized',
      message: 'Authentication required',
      loginUrl: '/auth/login',
    });
  }

  // Attach user to request
  req.user = req.session.user;
  next();
}

/**
 * Require specific group membership
 * Must be used after requireAuth
 */
export function requireGroup(allowedGroups) {
  return (req, res, next) => {
    // Skip if auth disabled
    if (!authConfig.app.authEnabled) {
      return next();
    }

    if (!req.user) {
      return res.status(401).json({
        error: 'Unauthorized',
        message: 'Authentication required',
      });
    }

    const userGroups = req.user.groups || [];
    const hasGroup = allowedGroups.some(g => userGroups.includes(g));

    if (!hasGroup) {
      return res.status(403).json({
        error: 'Forbidden',
        message: `Required group: ${allowedGroups.join(' or ')}`,
        userGroups,
      });
    }

    next();
  };
}

/**
 * Optional authentication - attach user if present but don't require it
 */
export function optionalAuth(req, res, next) {
  if (!authConfig.app.authEnabled) {
    req.user = null;
    return next();
  }

  if (req.session && req.session.user) {
    req.user = req.session.user;
  } else {
    req.user = null;
  }

  next();
}

/**
 * Check if user is admin
 */
export function isAdmin(user) {
  if (!user || !user.groups) return false;
  return user.groups.includes(authConfig.groups.admin);
}

/**
 * Authenticate WebSocket upgrade request
 * Returns user object or null
 */
export async function authenticateWebSocket(req, sessionStore) {
  // Skip auth if disabled
  if (!authConfig.app.authEnabled) {
    return { id: 'anonymous', email: 'anonymous@local', groups: ['agent-admin'] };
  }

  // Parse session ID from cookies
  const cookies = parseCookies(req.headers.cookie || '');
  const sessionCookie = cookies[authConfig.session.name];

  if (!sessionCookie) {
    console.log('[WS Auth] No session cookie found');
    return null;
  }

  // Session cookie format: s:sessionId.signature
  // We need to extract the session ID
  const sessionId = decodeSessionCookie(sessionCookie, authConfig.session.secret);

  if (!sessionId) {
    console.log('[WS Auth] Invalid session cookie');
    return null;
  }

  // Load session from store
  return new Promise((resolve) => {
    sessionStore.get(sessionId, (err, session) => {
      if (err || !session || !session.user) {
        console.log('[WS Auth] Session not found or invalid');
        resolve(null);
        return;
      }

      console.log(`[WS Auth] Authenticated user: ${session.user.email}`);
      resolve(session.user);
    });
  });
}

/**
 * Parse cookies from header string
 */
function parseCookies(cookieHeader) {
  const cookies = {};
  if (!cookieHeader) return cookies;

  cookieHeader.split(';').forEach(cookie => {
    const [name, ...rest] = cookie.trim().split('=');
    cookies[name] = rest.join('=');
  });

  return cookies;
}

/**
 * Decode express-session cookie
 * Cookie format: s:sessionId.signature (URL encoded)
 */
function decodeSessionCookie(cookie, secret) {
  try {
    // URL decode
    const decoded = decodeURIComponent(cookie);

    // Check for signed cookie prefix
    if (!decoded.startsWith('s:')) {
      return null;
    }

    // Extract session ID (before the signature)
    const withoutPrefix = decoded.substring(2);
    const dotIndex = withoutPrefix.lastIndexOf('.');

    if (dotIndex === -1) {
      return null;
    }

    return withoutPrefix.substring(0, dotIndex);
  } catch (e) {
    return null;
  }
}

export default {
  requireAuth,
  requireGroup,
  optionalAuth,
  isAdmin,
  authenticateWebSocket,
};
