import type { UserRole } from "@fitai/shared";
import { NextResponse } from "next/server";

/**
 * Check if a user can access data from a specific gym
 *
 * @param userRole - The role of the requesting user
 * @param userGymId - The gym ID of the requesting user (null for superAdmin)
 * @param targetGymId - The gym ID being accessed (undefined means all gyms)
 * @returns true if access is allowed
 *
 * @example
 * // SuperAdmin accessing any gym
 * canAccessGym("superAdmin", null, "gym_123") // true
 *
 * // Admin accessing their own gym
 * canAccessGym("admin", "gym_abc", "gym_abc") // true
 *
 * // Admin trying to access other gym
 * canAccessGym("admin", "gym_abc", "gym_xyz") // false
 */
export function canAccessGym(
  userRole: UserRole,
  userGymId: string | null,
  targetGymId: string | undefined,
): boolean {
  // SuperAdmin can access any gym
  if (userRole === "superAdmin") {
    return true;
  }

  // If no target gym specified, allow access to own gym
  if (targetGymId === undefined) {
    return true;
  }

  // Non-superAdmins must have a gymId
  if (!userGymId) {
    return false;
  }

  // Must match the gym
  return userGymId === targetGymId;
}

/**
 * Check if a user can manage (create/update/delete) another user
 * Based on role hierarchy and gym membership
 *
 * @param requesterRole - Role of the user making the request
 * @param requesterGymId - Gym ID of the requesting user
 * @param targetRole - Role of the user being managed
 * @param targetGymId - Gym ID of the user being managed
 * @returns true if management is allowed
 *
 * @example
 * // SuperAdmin can manage anyone
 * canManageUser("superAdmin", null, "admin", "gym_abc") // true
 *
 * // Admin can manage trainers and clients in their gym
 * canManageUser("admin", "gym_abc", "trainer", "gym_abc") // true
 * canManageUser("admin", "gym_abc", "client", "gym_abc") // true
 *
 * // Admin cannot manage users in other gyms
 * canManageUser("admin", "gym_abc", "trainer", "gym_xyz") // false
 *
 * // Trainer can manage clients in their gym
 * canManageUser("trainer", "gym_abc", "client", "gym_abc") // true
 */
export function canManageUser(
  requesterRole: UserRole,
  requesterGymId: string | null,
  targetRole: UserRole,
  targetGymId: string | null,
): boolean {
  // SuperAdmin can manage anyone
  if (requesterRole === "superAdmin") {
    return true;
  }

  // Role hierarchy: admin > trainer > client
  const roleHierarchy: Record<UserRole, number> = {
    superAdmin: 4,
    admin: 3,
    trainer: 2,
    client: 1,
  };

  const requesterLevel = roleHierarchy[requesterRole];
  const targetLevel = roleHierarchy[targetRole];

  // Cannot manage users at same or higher level
  if (requesterLevel <= targetLevel) {
    return false;
  }

  // Must have gym access
  if (!requesterGymId) {
    return false;
  }

  // For admin/trainer, target must be in same gym
  if (requesterRole === "admin" || requesterRole === "trainer") {
    return requesterGymId === targetGymId;
  }

  return false;
}

/**
 * Check if a trainer can access a specific client's data
 * Trainer must be assigned to that client via trainerClients table
 *
 * @param trainerGymId - Gym ID of the trainer
 * @param clientGymId - Gym ID of the client
 * @returns true if in same gym
 *
 * @note In a more complex system, this would query trainerClients table
 * For now, we use gym-based access (trainer and client in same gym)
 */
export function canTrainerAccessClient(
  trainerGymId: string | null,
  clientGymId: string | null,
): boolean {
  if (!trainerGymId || !clientGymId) {
    return false;
  }
  return trainerGymId === clientGymId;
}

/**
 * Get the roles that a specific role can invite
 * Based on role hierarchy
 *
 * @param role - The role wanting to invite
 * @returns Array of roles that can be invited
 *
 * @example
 * getInvitableRoles("superAdmin") // ["admin", "trainer", "client"]
 * getInvitableRoles("admin")      // ["trainer", "client"]
 * getInvitableRoles("trainer")    // ["client"]
 * getInvitableRoles("client")     // []
 */
export function getInvitableRoles(role: UserRole): UserRole[] {
  const invitationRules: Record<UserRole, UserRole[]> = {
    superAdmin: ["admin", "trainer", "client"],
    admin: ["trainer", "client"],
    trainer: ["client"],
    client: [],
  };

  return invitationRules[role] ?? [];
}

/**
 * Validate gym access and return error response if denied
 * Use this in API routes to enforce gym-based access control
 *
 * @param request - NextRequest for getting query params
 * @param userRole - Current user's role
 * @param userGymId - Current user's gym ID
 * @param targetGymId - Gym being accessed (optional)
 * @returns NextResponse if denied, undefined if allowed
 *
 * @example
 * export async function GET(request: NextRequest) {
 *   const error = await validateGymAccess(request, role, gymId);
 *   if (error) return error;
 *   // ... proceed
 * }
 */
export function validateGymAccess(
  userRole: UserRole,
  userGymId: string | null,
  targetGymId?: string,
): NextResponse | undefined {
  if (!canAccessGym(userRole, userGymId, targetGymId)) {
    return NextResponse.json(
      { error: "Forbidden - Cannot access this gym's data" },
      { status: 403 },
    );
  }
  return undefined;
}

/**
 * Get filter condition for gym-scoped queries
 * Returns appropriate filter based on user role
 *
 * @param userRole - Current user's role
 * @param userGymId - Current user's gym ID
 * @returns Filter object or undefined (no filter = all gyms)
 *
 * @example
 * // For superAdmin: returns undefined (no filter)
 * getGymFilter("superAdmin", null) // undefined
 *
 * // For admin: returns { gymId: "gym_abc" }
 * getGymFilter("admin", "gym_abc") // { gymId: "gym_abc" }
 */
export function getGymFilter(
  userRole: UserRole,
  userGymId: string | null,
): { gymId: string } | undefined {
  // SuperAdmin sees all gyms
  if (userRole === "superAdmin") {
    return undefined;
  }

  // Other roles filtered by their gym
  if (userGymId) {
    return { gymId: userGymId };
  }

  // No gym assigned - return filter that matches nothing
  return { gymId: "" };
}

/**
 * Get all gym IDs a user can access
 * SuperAdmin gets all gyms, others get only their own
 *
 * @param userRole - Current user's role
 * @param userGymId - Current user's gym ID
 * @param allGymIds - List of all gym IDs in system (for superAdmin)
 * @returns Array of accessible gym IDs
 *
 * @example
 * getAccessibleGymIds("admin", "gym_abc", ["gym_abc", "gym_xyz"])
 * // Returns: ["gym_abc"]
 *
 * getAccessibleGymIds("superAdmin", null, ["gym_abc", "gym_xyz"])
 * // Returns: ["gym_abc", "gym_xyz"]
 */
export function getAccessibleGymIds(
  userRole: UserRole,
  userGymId: string | null,
  allGymIds: string[],
): string[] {
  if (userRole === "superAdmin") {
    return allGymIds;
  }

  if (userGymId) {
    return [userGymId];
  }

  return [];
}
