export interface AuthenticatedUser {
  id: string;
  email: string;
  username: string;
  name: string;
  authMethod: string;
  groups: string[];
}

export interface AuthSession {
  user: AuthenticatedUser | null;
  authenticated: boolean;
  groups: string[];
}

/**
 * Check if the request is authenticated via Keycloak OIDC session
 */
export const isAuthenticated = async (event: any): Promise<boolean> => {
  console.log('[auth] Checking authentication for:', event.node.req.url);

  // Check OIDC session authentication
  try {
    const oidcSession = getCookie(event, 'nuxt-oidc-auth');
    console.log('[auth] OIDC session cookie:', oidcSession ? 'present' : 'not found');
    
    if (!oidcSession) {
      console.log('[auth] No OIDC session found');
      return false;
    }

    // Parse and validate session data
    let sessionData;
    try {
      sessionData = JSON.parse(oidcSession);
    } catch (parseError) {
      console.error('[auth] Failed to parse session cookie:', parseError);
      return false;
    }

    // Validate session structure
    if (!sessionData.user || !sessionData.accessToken) {
      console.error('[auth] Invalid session structure:', {
        hasUser: !!sessionData.user,
        hasAccessToken: !!sessionData.accessToken
      });
      return false;
    }

    // Check if session is still valid
    if (sessionData.expiresAt && Date.now() > sessionData.expiresAt) {
      console.log('[auth] Session expired:', {
        expiresAt: sessionData.expiresAt,
        currentTime: Date.now(),
        expiredSince: Date.now() - sessionData.expiresAt
      });
      return false;
    }

    console.log('[auth] Valid OIDC session found for user:', {
      id: sessionData.user.id,
      email: sessionData.user.email
    });
    return true;

  } catch (error) {
    console.error('[auth] OIDC session check failed:', error);
    return false;
  }
}

/**
 * Get the full authenticated session with user and groups
 */
export const getAuthSession = async (event: any): Promise<AuthSession> => {
  try {
    const sessionData = await $fetch('/api/auth/session', {
      headers: {
        cookie: getHeader(event, 'cookie') || ''
      }
    }) as AuthSession;

    return sessionData;
  } catch (error) {
    console.error('[auth] Failed to get auth session:', error);
    return { user: null, authenticated: false, groups: [] };
  }
}

/**
 * Get user groups from the session
 */
export const getUserGroups = async (event: any): Promise<string[]> => {
  const session = await getAuthSession(event);
  return session.groups || [];
}

/**
 * Check if user has specific role/group
 */
export const hasRole = async (event: any, role: string): Promise<boolean> => {
  const groups = await getUserGroups(event);
  return groups.includes(role);
}

/**
 * Check if user has any of the specified roles
 */
export const hasAnyRole = async (event: any, roles: string[]): Promise<boolean> => {
  const groups = await getUserGroups(event);
  return roles.some(role => groups.includes(role));
}

/**
 * Require authentication and optionally specific roles
 */
export const requireAuth = async (event: any, requiredRoles?: string[]): Promise<AuthSession> => {
  console.log('[requireAuth] Checking authentication for:', event.node.req.url, 'Required roles:', requiredRoles);

  // First check for internal API authentication
  const internalAuth = checkInternalAuth(event);
  if (internalAuth) {
    console.log('[requireAuth] Internal API authentication successful');
    return {
      user: { 
        id: 'system', 
        email: 'system@internal', 
        username: 'system',
        name: 'System',
        authMethod: 'internal',
        groups: ['admin'] // Internal calls have admin privileges
      },
      authenticated: true,
      groups: ['admin']
    };
  }

  // Get full session with groups
  const session = await getAuthSession(event);
  
  if (!session.authenticated || !session.user) {
    console.log('[requireAuth] Authentication failed for:', event.node.req.url);
    throw createError({ 
      statusCode: 401, 
      statusMessage: "Authentication required. Please login." 
    });
  }

  // Check role requirements if specified
  if (requiredRoles && requiredRoles.length > 0) {
    const userGroups = session.groups || [];
    const hasRequiredRole = requiredRoles.some(role => userGroups.includes(role));
    
    if (!hasRequiredRole) {
      console.log('[requireAuth] Access denied. User groups:', userGroups, 'Required roles:', requiredRoles);
      throw createError({
        statusCode: 403,
        statusMessage: 'Insufficient permissions. This action requires one of the following roles: ' + requiredRoles.join(', ')
      });
    }
  }

  console.log('[requireAuth] Authentication successful for user:', session.user.email, 'Groups:', session.groups);
  return session;
}

/**
 * Check if the request is from an internal service/background task
 */
const checkInternalAuth = (event: any): boolean => {
  const headers = event.node.req.headers;
  
  // Check for internal service header with the system tag
  const xTag = headers['x-tag'];
  const xInternalSecret = headers['x-internal-secret'];
  
  // System tag authentication (for background tasks)
  if (xTag === '094ut234') {
    console.log('[auth] Internal system tag authentication successful');
    return true;
  }
  
  // Internal secret authentication (if set in environment)
  const internalSecret = process.env.INTERNAL_API_SECRET;
  if (internalSecret && xInternalSecret === internalSecret) {
    console.log('[auth] Internal secret authentication successful');
    return true;
  }
  
  // Check if request is from localhost (same container)
  const xForwardedFor = headers['x-forwarded-for'];
  const xRealIp = headers['x-real-ip'];
  const remoteAddress = event.node.req.socket?.remoteAddress;
  
  const isLocalhost = !xForwardedFor && !xRealIp && 
    (remoteAddress === '127.0.0.1' || remoteAddress === '::1' || remoteAddress === '::ffff:127.0.0.1');
  
  if (isLocalhost && xTag) {
    console.log('[auth] Localhost with system tag authentication successful');
    return true;
  }
  
  return false;
}

/**
 * Get the authenticated user from the session
 */
export const getAuthenticatedUser = async (event: any): Promise<AuthenticatedUser | null> => {
  try {
    const session = await getAuthSession(event);
    return session.user;
  } catch (error) {
    console.error('[getAuthenticatedUser] Error:', error);
    return null;
  }
}

/**
 * Authorization helper functions for common roles
 */
export const requireAdmin = async (event: any): Promise<AuthSession> => {
  return requireAuth(event, ['admin']);
}

export const requireSalesOrAdmin = async (event: any): Promise<AuthSession> => {
  return requireAuth(event, ['sales', 'admin']);
}

export const requireUserOrAbove = async (event: any): Promise<AuthSession> => {
  return requireAuth(event, ['user', 'sales', 'admin']);
}

function parseCookies(cookieString: string): Record<string, string> {
  return cookieString.split(';').reduce((cookies: Record<string, string>, cookie) => {
    const [name, value] = cookie.trim().split('=');
    if (name && value) {
      cookies[name] = value;
    }
    return cookies;
  }, {});
}
