import { db } from '../db/db_index';
import { users, userDetails, orders, orderItems, complaints, notifCreds, unloggedUserTokens, userIncidents, orderStatus } from '../db/schema';
import { eq, sql, desc, asc, count, max, inArray, like } from 'drizzle-orm';

export async function createUserByMobile(mobile: string): Promise<any> {
  const [newUser] = await db
    .insert(users)
    .values({
      name: null,
      email: null,
      mobile,
    })
    .returning();

  return newUser;
}

export async function getUserByMobile(mobile: string): Promise<any | null> {
  const [existingUser] = await db
    .select()
    .from(users)
    .where(eq(users.mobile, mobile))
    .limit(1);

  return existingUser || null;
}

export async function getUnresolvedComplaintsCount(): Promise<number> {
  const result = await db
    .select({ count: count(complaints.id) })
    .from(complaints)
    .where(eq(complaints.isResolved, false));
  
  return result[0]?.count || 0;
}

export async function getAllUsersWithFilters(
  limit: number,
  cursor?: number,
  search?: string
): Promise<{ users: any[]; hasMore: boolean }> {
  const whereConditions = [];
  
  if (search && search.trim()) {
    whereConditions.push(sql`${users.mobile} LIKE ${`%${search.trim()}%`}`);
  }
  
  if (cursor) {
    whereConditions.push(sql`${users.id} > ${cursor}`);
  }

  const usersList = await db
    .select({
      id: users.id,
      name: users.name,
      mobile: users.mobile,
      createdAt: users.createdAt,
    })
    .from(users)
    .where(whereConditions.length > 0 ? sql.join(whereConditions, sql` AND `) : undefined)
    .orderBy(asc(users.id))
    .limit(limit + 1);

  const hasMore = usersList.length > limit;
  const usersToReturn = hasMore ? usersList.slice(0, limit) : usersList;

  return { users: usersToReturn, hasMore };
}

export async function getOrderCountsByUserIds(userIds: number[]): Promise<{ userId: number; totalOrders: number }[]> {
  if (userIds.length === 0) return [];
  
  return await db
    .select({
      userId: orders.userId,
      totalOrders: count(orders.id),
    })
    .from(orders)
    .where(sql`${orders.userId} IN (${sql.join(userIds, sql`, `)})`)
    .groupBy(orders.userId);
}

export async function getLastOrdersByUserIds(userIds: number[]): Promise<{ userId: number; lastOrderDate: Date | null }[]> {
  if (userIds.length === 0) return [];
  
  return await db
    .select({
      userId: orders.userId,
      lastOrderDate: max(orders.createdAt),
    })
    .from(orders)
    .where(sql`${orders.userId} IN (${sql.join(userIds, sql`, `)})`)
    .groupBy(orders.userId);
}

export async function getSuspensionStatusesByUserIds(userIds: number[]): Promise<{ userId: number; isSuspended: boolean }[]> {
  if (userIds.length === 0) return [];
  
  return await db
    .select({
      userId: userDetails.userId,
      isSuspended: userDetails.isSuspended,
    })
    .from(userDetails)
    .where(sql`${userDetails.userId} IN (${sql.join(userIds, sql`, `)})`);
}

export async function getUserBasicInfo(userId: number): Promise<any | null> {
  const user = await db
    .select({
      id: users.id,
      name: users.name,
      mobile: users.mobile,
      createdAt: users.createdAt,
    })
    .from(users)
    .where(eq(users.id, userId))
    .limit(1);

  return user[0] || null;
}

export async function getUserSuspensionStatus(userId: number): Promise<boolean> {
  const userDetail = await db
    .select({
      isSuspended: userDetails.isSuspended,
    })
    .from(userDetails)
    .where(eq(userDetails.userId, userId))
    .limit(1);

  return userDetail[0]?.isSuspended ?? false;
}

export async function getUserOrders(userId: number): Promise<any[]> {
  return await db
    .select({
      id: orders.id,
      readableId: orders.readableId,
      totalAmount: orders.totalAmount,
      createdAt: orders.createdAt,
      isFlashDelivery: orders.isFlashDelivery,
    })
    .from(orders)
    .where(eq(orders.userId, userId))
    .orderBy(desc(orders.createdAt));
}

export async function getOrderStatusesByOrderIds(orderIds: number[]): Promise<{ orderId: number; isDelivered: boolean; isCancelled: boolean }[]> {
  if (orderIds.length === 0) return [];
  
  return await db
    .select({
      orderId: orderStatus.orderId,
      isDelivered: orderStatus.isDelivered,
      isCancelled: orderStatus.isCancelled,
    })
    .from(orderStatus)
    .where(sql`${orderStatus.orderId} IN (${sql.join(orderIds, sql`, `)})`);
}

export async function getItemCountsByOrderIds(orderIds: number[]): Promise<{ orderId: number; itemCount: number }[]> {
  if (orderIds.length === 0) return [];
  
  return await db
    .select({
      orderId: orderItems.orderId,
      itemCount: count(orderItems.id),
    })
    .from(orderItems)
    .where(sql`${orderItems.orderId} IN (${sql.join(orderIds, sql`, `)})`)
    .groupBy(orderItems.orderId);
}

export async function upsertUserSuspension(userId: number, isSuspended: boolean): Promise<void> {
  const existingDetail = await db
    .select({ id: userDetails.id })
    .from(userDetails)
    .where(eq(userDetails.userId, userId))
    .limit(1);

  if (existingDetail.length > 0) {
    await db
      .update(userDetails)
      .set({ isSuspended })
      .where(eq(userDetails.userId, userId));
  } else {
    await db
      .insert(userDetails)
      .values({
        userId,
        isSuspended,
      });
  }
}

export async function searchUsers(search?: string): Promise<any[]> {
  if (search && search.trim()) {
    return await db
      .select({
        id: users.id,
        name: users.name,
        mobile: users.mobile,
      })
      .from(users)
      .where(sql`${users.mobile} LIKE ${`%${search.trim()}%`} OR ${users.name} LIKE ${`%${search.trim()}%`}`);
  } else {
    return await db
      .select({
        id: users.id,
        name: users.name,
        mobile: users.mobile,
      })
      .from(users);
  }
}

export async function getAllNotifCreds(): Promise<{ userId: number }[]> {
  return await db
    .select({ userId: notifCreds.userId })
    .from(notifCreds);
}

export async function getAllUnloggedTokens(): Promise<{ token: string }[]> {
  return await db
    .select({ token: unloggedUserTokens.token })
    .from(unloggedUserTokens);
}

export async function getNotifTokensByUserIds(userIds: number[]): Promise<{ token: string }[]> {
  return await db
    .select({ token: notifCreds.token })
    .from(notifCreds)
    .where(inArray(notifCreds.userId, userIds));
}

export async function getUserIncidentsWithRelations(userId: number): Promise<any[]> {
  return await db.query.userIncidents.findMany({
    where: eq(userIncidents.userId, userId),
    with: {
      order: {
        with: {
          orderStatus: true,
        },
      },
      addedBy: true,
    },
    orderBy: desc(userIncidents.dateAdded),
  });
}

export async function createUserIncident(
  userId: number,
  orderId: number | undefined,
  adminComment: string | undefined,
  adminUserId: number,
  negativityScore: number | undefined
): Promise<any> {
  const [incident] = await db.insert(userIncidents)
    .values({
      userId,
      orderId,
      adminComment,
      addedBy: adminUserId,
      negativityScore,
    })
    .returning();

  return incident;
}
