import { and, desc, eq, gte, like, lte, or, sql } from "drizzle-orm";
import { drizzle } from "drizzle-orm/mysql2";
import type { InsertUser } from "../drizzle/schema.ts";
import {
  auditLogs, bingoCards, bingoRooms, bingoSessions,
  casinoGames, chatMessages, coinPackages, dailyBonuses, fraudAlerts,
  gameSessions, kycDocuments, miniGameRounds, platformSettings, pokerHands, pokerTables,
  pokerTournaments, recentlyPlayed, restrictedStates, rtpOverrides,
  scRedemptions, sportBets, sportEvents, staff, supportTickets,
  ticketMessages, timeClock, transactions, users, wallets,
  adminOnboardingProgress, adminProfiles, adminDeviceRegistrations, adminDelegations,
  adminDelegationApprovals, adminDelegationNotes, adminShifts, adminShiftAssignments,
  adminShiftSwaps, achievements, aiEmployees, aiEmployeeChats, aiEmployeeTasks,
  aiGeneratedGames, aiSocialContent, allGames, authAuditLog, customGames,
  dailySpins, emailVerifications, eventParticipation, friends, gameAnalytics,
  gameChat, gameConfigurations, gameLibrary, gameRecommendations, gameStats,
  gameTemplates, jackpotHistory, knowledgeArticles, knowledgeArticleVotes, leaderboards,
  magicLinkTokens, multiplierBoosts, notificationPreferences, notifications, oauthAccounts,
  onboardingAnalytics, paymentMethods, pgSoftGames, pgSoftGameSessions, pgSoftGameTransactions,
  playerProfiles, poolSharkAchievements, poolSharkLeaderboards, poolSharkMatches,
  poolSharkParticipants, poolSharkTables, poolSharkWaitingLists, progressiveJackpots,
  promoBanners, rateLimitLog, referrals, seasonalEvents, socialStream, spinHistory,
  streamInteractions, tournamentParticipants, tournamentSnapshots, tournaments,
  twoFactorSecrets, userAchievements, userFavorites, userSessions, userVipStatus,
  vipTiers, winShareEvents
} from "../drizzle/schema.ts";

let _db: ReturnType<typeof drizzle> | null = null;

function isValidDatabaseUrl(databaseUrl: string) {
  try {
    new URL(databaseUrl);
    return true;
  } catch {
    return false;
  }
}

export async function getDb() {
  if (!_db && process.env.DATABASE_URL) {
    if (!isValidDatabaseUrl(process.env.DATABASE_URL)) {
      console.warn("[Database] Invalid DATABASE_URL provided");
      return null;
    }

    try {
      const drizzleInstance = drizzle(process.env.DATABASE_URL);
      
      // Map of table names to table objects - includes all schema tables
      const tableMap: Record<string, any> = {
        users, wallets, transactions, gameSessions, auditLogs, kycDocuments,
        casinoGames, bingoCards, bingoRooms, bingoSessions, chatMessages,
        coinPackages, dailyBonuses, fraudAlerts, miniGameRounds, platformSettings,
        pokerHands, pokerTables, pokerTournaments, recentlyPlayed, restrictedStates,
        rtpOverrides, scRedemptions, sportBets, sportEvents, staff, supportTickets,
        ticketMessages, timeClock, adminOnboardingProgress, adminProfiles, adminDeviceRegistrations,
        adminDelegations, adminDelegationApprovals, adminDelegationNotes, adminShifts,
        adminShiftAssignments, adminShiftSwaps, achievements, aiEmployees, aiEmployeeChats,
        aiEmployeeTasks, aiGeneratedGames, aiSocialContent, allGames, authAuditLog,
        customGames, dailySpins, emailVerifications, eventParticipation, friends,
        gameAnalytics, gameChat, gameConfigurations, gameLibrary, gameRecommendations,
        gameStats, gameTemplates, jackpotHistory, knowledgeArticles, knowledgeArticleVotes,
        leaderboards, magicLinkTokens, multiplierBoosts, notificationPreferences, notifications,
        oauthAccounts, onboardingAnalytics, paymentMethods, pgSoftGames, pgSoftGameSessions,
        pgSoftGameTransactions, playerProfiles, poolSharkAchievements, poolSharkLeaderboards,
        poolSharkMatches, poolSharkParticipants, poolSharkTables, poolSharkWaitingLists,
        progressiveJackpots, promoBanners, rateLimitLog, referrals, seasonalEvents,
        socialStream, spinHistory, streamInteractions, tournamentParticipants, tournamentSnapshots,
        tournaments, twoFactorSecrets, userAchievements, userFavorites, userSessions,
        userVipStatus, vipTiers, winShareEvents
      };
      
      // Create query proxy to support .query.table.findFirst/findMany pattern
      const queryProxy = new Proxy({}, {
        get: (target, tableName: string | symbol) => ({
          findFirst: async (options: any) => {
            const table = tableMap[tableName as string];
            if (!table) throw new Error(`Table ${String(tableName)} not found`);
            const result = await drizzleInstance.select().from(table).where(options.where).limit(1);
            return result[0] || null;
          },
          findMany: async (options: any) => {
            const table = tableMap[tableName as string];
            if (!table) throw new Error(`Table ${String(tableName)} not found`);
            return await drizzleInstance.select().from(table).where(options.where);
          }
        })
      });
      
      // Attach query proxy to drizzle instance
      _db = Object.assign(drizzleInstance, { query: queryProxy }) as any;
    } catch (error) {
      console.warn("[Database] Failed to connect:", error);
      _db = null;
    }
  }
  return _db;
}

// ─── USER HELPERS ─────────────────────────────────────────────────────────────

export async function upsertUser(user: InsertUser) {
  if (!user.openId) throw new Error("User openId is required");
  const db = await getDb();
  if (!db) return undefined;
  
  try {
    // Build insert values with only the columns that exist
    const insertValues: any = {
      openId: user.openId,
      lastSignedIn: user.lastSignedIn || new Date(),
    };
    
    // Add optional fields only if provided
    if (user.name !== undefined) insertValues.name = user.name;
    if (user.email !== undefined) insertValues.email = user.email;
    if (user.loginMethod !== undefined) insertValues.loginMethod = user.loginMethod;
    if (user.passwordHash !== undefined) insertValues.passwordHash = user.passwordHash;
    
    // Build update set
    const updateSet: any = { lastSignedIn: insertValues.lastSignedIn };
    if (user.name !== undefined) updateSet.name = user.name;
    if (user.email !== undefined) updateSet.email = user.email;
    if (user.loginMethod !== undefined) updateSet.loginMethod = user.loginMethod;
    if (user.passwordHash !== undefined) updateSet.passwordHash = user.passwordHash;
    
    // Use Drizzle insert with onDuplicateKeyUpdate
    await db.insert(users).values(insertValues).onDuplicateKeyUpdate({ set: updateSet });
  } catch (error) {
    console.error("[DB] upsertUser error:", error);
    throw error;
  }
  
  return await getUserByOpenId(user.openId);
}

export async function getUserByOpenId(openId: string) {
  const db = await getDb();
  if (!db) return undefined;
  const result = await db.select({
    id: users.id,
    openId: users.openId,
    name: users.name,
    email: users.email,
    loginMethod: users.loginMethod,
    role: users.role,
    createdAt: users.createdAt,
    updatedAt: users.updatedAt,
    lastSignedIn: users.lastSignedIn,
  }).from(users).where(eq(users.openId, openId)).limit(1);
  return result[0];
}

export async function getUserById(id: number) {
  const db = await getDb();
  if (!db) return undefined;
  const result = await db.select({
    id: users.id,
    openId: users.openId,
    name: users.name,
    email: users.email,
    loginMethod: users.loginMethod,
    role: users.role,
    createdAt: users.createdAt,
    updatedAt: users.updatedAt,
    lastSignedIn: users.lastSignedIn,
  }).from(users).where(eq(users.id, id)).limit(1);
  return result[0];
}

export async function getUserByEmail(email: string) {
  const db = await getDb();
  if (!db) return undefined;
  const result = await db.select({
    id: users.id,
    openId: users.openId,
    name: users.name,
    email: users.email,
    loginMethod: users.loginMethod,
    role: users.role,
    createdAt: users.createdAt,
    updatedAt: users.updatedAt,
    lastSignedIn: users.lastSignedIn,
  }).from(users).where(eq(users.email, email)).limit(1);
  return result[0];
}

export async function getAllUsers(limit = 50, offset = 0, search?: string) {
  const db = await getDb();
  if (!db) return [];
  const q = db.select({
    id: users.id,
    openId: users.openId,
    name: users.name,
    email: users.email,
    loginMethod: users.loginMethod,
    role: users.role,
    createdAt: users.createdAt,
    updatedAt: users.updatedAt,
    lastSignedIn: users.lastSignedIn,
  }).from(users);
  if (search) {
    return q.where(or(like(users.username, `%${search}%`), like(users.email, `%${search}%`), like(users.name, `%${search}%`))).limit(limit).offset(offset).orderBy(desc(users.createdAt));
  }
  return q.limit(limit).offset(offset).orderBy(desc(users.createdAt));
}

export async function updateUser(id: number, data: Partial<InsertUser>) {
  const db = await getDb();
  if (!db) return;
  await db.update(users).set(data).where(eq(users.id, id));
}

export async function getUserBySocialId(socialId: string, provider: string) {
  const db = await getDb();
  if (!db) return undefined;
  const result = await db.select({
    id: users.id,
    openId: users.openId,
    name: users.name,
    email: users.email,
    loginMethod: users.loginMethod,
    role: users.role,
    createdAt: users.createdAt,
    updatedAt: users.updatedAt,
    lastSignedIn: users.lastSignedIn,
  }).from(users).where(
    and(eq(users.socialId, socialId), eq(users.socialProvider, provider))
  ).limit(1);
  return result[0];
}

export async function getLinkedAccounts(userId: number) {
  const db = await getDb();
  if (!db) return [];
  const user = await getUserById(userId);
  if (!user) return [];
  
  // Return linked accounts - for now just the primary one
  // In a real app, you'd have a separate linked_accounts table
  const accounts = [];
  if (user.socialProvider && user.socialId) {
    accounts.push({
      userId,
      provider: user.socialProvider,
      socialId: user.socialId,
      email: user.email,
      displayName: user.name,
      linkedAt: user.createdAt,
    });
  }
  return accounts;
}

export async function addLinkedAccount(data: {
  userId: number;
  provider: string;
  socialId: string;
  email?: string;
  displayName?: string;
  linkedAt: Date;
}) {
  // In a real app, you'd insert into a linked_accounts table
  // For now, this is a placeholder
  return data;
}

export async function removeLinkedAccount(userId: number, provider: string) {
  // In a real app, you'd delete from a linked_accounts table
  // For now, this is a placeholder
  return true;
}

// ─── WALLET HELPERS ───────────────────────────────────────────────────────────

export async function getOrCreateWallet(userId: number) {
  const db = await getDb();
  if (!db) throw new Error("DB unavailable");
  const existing = await db.select().from(wallets).where(eq(wallets.userId, userId)).limit(1);
  if (existing[0]) return existing[0];
  await db.insert(wallets).values({ userId, gcBalance: "5000.00", scBalance: "2.00", lifetimeGcEarned: "5000.00", lifetimeScEarned: "2.00" });
  const created = await db.select().from(wallets).where(eq(wallets.userId, userId)).limit(1);
  return created[0];
}

export async function creditWallet(userId: number, currency: "GC" | "SC", amount: number, type: string, description: string, referenceId?: string, referenceType?: string) {
  const db = await getDb();
  if (!db) throw new Error("DB unavailable");
  const wallet = await getOrCreateWallet(userId);
  const balanceBefore = parseFloat(currency === "GC" ? wallet.gcBalance : wallet.scBalance);
  const balanceAfter = balanceBefore + amount;
  if (currency === "GC") {
    await db.update(wallets).set({ gcBalance: balanceAfter.toFixed(2), lifetimeGcEarned: (parseFloat(wallet.lifetimeGcEarned) + amount).toFixed(2) }).where(eq(wallets.userId, userId));
  } else {
    await db.update(wallets).set({ scBalance: balanceAfter.toFixed(2), lifetimeScEarned: (parseFloat(wallet.lifetimeScEarned) + amount).toFixed(2) }).where(eq(wallets.userId, userId));
  }
  await db.insert(transactions).values({ userId: userId, type: type as any, currency: currency as any, amount: amount.toFixed(2), balanceBefore: balanceBefore.toFixed(2), balanceAfter: balanceAfter.toFixed(2), description: description || '', referenceId: referenceId || null, referenceType: referenceType || null } as any);
  return balanceAfter;
}

export async function debitWallet(userId: number, currency: "GC" | "SC", amount: number, type: string, description: string, referenceId?: string, referenceType?: string) {
  const db = await getDb();
  if (!db) throw new Error("DB unavailable");
  const wallet = await getOrCreateWallet(userId);
  const balanceBefore = parseFloat(currency === "GC" ? wallet.gcBalance : wallet.scBalance);
  if (balanceBefore < amount) throw new Error("Insufficient balance");
  const balanceAfter = balanceBefore - amount;
  if (currency === "GC") {
    await db.update(wallets).set({ gcBalance: balanceAfter.toFixed(2) }).where(eq(wallets.userId, userId));
  } else {
    await db.update(wallets).set({ scBalance: balanceAfter.toFixed(2) }).where(eq(wallets.userId, userId));
  }
  await db.insert(transactions).values({ userId: userId, type: type as any, currency: currency as any, amount: amount.toFixed(2), balanceBefore: balanceBefore.toFixed(2), balanceAfter: balanceAfter.toFixed(2), description: description || '', referenceId: referenceId || null, referenceType: referenceType || null } as any);
  return balanceAfter;
}

export async function getTransactions(userId: number, limit = 20, offset = 0) {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(transactions).where(eq(transactions.userId, userId)).orderBy(desc(transactions.createdAt)).limit(limit).offset(offset);
}

// ─── AUDIT LOG HELPERS ────────────────────────────────────────────────────────

export async function writeAuditLog(data: { actorId?: number; actorRole?: string; targetUserId?: number; action: string; category: "auth" | "wallet" | "game" | "admin" | "kyc" | "staff" | "system" | "fraud"; details?: unknown; ipAddress?: string; userAgent?: string }) {
  const db = await getDb();
  if (!db) return;
  await db.insert(auditLogs).values({ ...data, details: data.details ? JSON.stringify(data.details) : null });
}

export async function getAuditLogs(limit = 50, offset = 0, category?: string, userId?: number) {
  const db = await getDb();
  if (!db) return [];
  const conditions = [];
  if (category) conditions.push(eq(auditLogs.category, category as any));
  if (userId) conditions.push(eq(auditLogs.actorId, userId));
  const q = db.select().from(auditLogs).orderBy(desc(auditLogs.createdAt)).limit(limit).offset(offset);
  if (conditions.length > 0) return q.where(and(...conditions));
  return q;
}

// ─── CASINO GAME HELPERS ──────────────────────────────────────────────────────

export async function getCasinoGames(opts: { limit?: number; offset?: number; category?: string; provider?: string; search?: string; featured?: boolean }) {
  const db = await getDb();
  if (!db) return [];
  const { limit = 24, offset = 0, category, provider, search, featured } = opts;
  const conditions = [eq(casinoGames.isActive, true)];
  if (category && category !== "all") conditions.push(eq(casinoGames.category, category as any));
  if (provider) conditions.push(eq(casinoGames.provider, provider));
  if (search) conditions.push(like(casinoGames.title, `%${search}%`));
  if (featured) conditions.push(eq(casinoGames.isFeatured, true));
  return db.select().from(casinoGames).where(and(...conditions)).orderBy(desc(casinoGames.playCount)).limit(limit).offset(offset);
}

export async function getGameById(id: number) {
  const db = await getDb();
  if (!db) return undefined;
  const result = await db.select().from(casinoGames).where(eq(casinoGames.id, id)).limit(1);
  return result[0];
}

export async function getProviders() {
  const db = await getDb();
  if (!db) return [];
  const result = await db.selectDistinct({ provider: casinoGames.provider }).from(casinoGames).where(eq(casinoGames.isActive, true));
  return result.map(r => r.provider);
}

export async function recordGameSession(data: { userId: number; gameId: number; currency: "GC" | "SC"; betAmount: number; winAmount: number; multiplier: number; outcome: unknown; rtpApplied: number }) {
  const db = await getDb();
  if (!db) return;
  await db.insert(gameSessions).values({ ...data, betAmount: data.betAmount.toFixed(2), winAmount: data.winAmount.toFixed(2), outcome: JSON.stringify(data.outcome) });
  await db.update(casinoGames).set({ playCount: sql`${casinoGames.playCount} + 1` }).where(eq(casinoGames.id, data.gameId));
  // Update recently played
  const existing = await db.select().from(recentlyPlayed).where(and(eq(recentlyPlayed.userId, data.userId), eq(recentlyPlayed.gameId, data.gameId))).limit(1);
  if (existing.length > 0) {
    await db.update(recentlyPlayed).set({ playedAt: new Date() }).where(eq(recentlyPlayed.id, existing[0].id));
  } else {
    await db.insert(recentlyPlayed).values({ userId: data.userId, gameId: data.gameId });
  }
}

export async function getRecentlyPlayed(userId: number) {
  const db = await getDb();
  if (!db) return [];
  const recent = await db.select().from(recentlyPlayed).where(eq(recentlyPlayed.userId, userId)).orderBy(desc(recentlyPlayed.playedAt)).limit(10);
  if (recent.length === 0) return [];
  const gameIds = recent.map(r => r.gameId);
  return db.select().from(casinoGames).where(sql`${casinoGames.id} IN (${sql.join(gameIds.map(id => sql`${id}`), sql`, `)})`);
}

export async function getRtpOverride(userId: number, gameId: number): Promise<number | null> {
  const db = await getDb();
  if (!db) return null;
  const now = new Date();
  const userOverride = await db.select().from(rtpOverrides).where(and(eq(rtpOverrides.userId, userId), eq(rtpOverrides.gameId, gameId), or(sql`${rtpOverrides.expiresAt} IS NULL`, gte(rtpOverrides.expiresAt, now)))).limit(1);
  if (userOverride[0]) return userOverride[0].rtpOverride;
  const gameOverride = await db.select().from(rtpOverrides).where(and(sql`${rtpOverrides.userId} IS NULL`, eq(rtpOverrides.gameId, gameId), or(sql`${rtpOverrides.expiresAt} IS NULL`, gte(rtpOverrides.expiresAt, now)))).limit(1);
  if (gameOverride[0]) return gameOverride[0].rtpOverride;
  return null;
}

// ─── DAILY BONUS HELPERS ──────────────────────────────────────────────────────

export async function getLastDailyBonus(userId: number) {
  const db = await getDb();
  if (!db) return null;
  const result = await db.select().from(dailyBonuses).where(eq(dailyBonuses.userId, userId)).orderBy(desc(dailyBonuses.claimedAt)).limit(1);
  return result[0] ?? null;
}

export async function claimDailyBonus(userId: number, spinResult: number, gcAmount: number, scAmount: number) {
  const db = await getDb();
  if (!db) throw new Error("DB unavailable");
  await db.insert(dailyBonuses).values({ userId, spinResult, gcAmount: gcAmount.toFixed(2), scAmount: scAmount.toFixed(2) });
  if (gcAmount > 0) await creditWallet(userId, "GC", gcAmount, "daily_bonus", "Daily bonus wheel spin");
  if (scAmount > 0) await creditWallet(userId, "SC", scAmount, "daily_bonus", "Daily bonus wheel spin - SC reward");
}

// ─── KYC HELPERS ─────────────────────────────────────────────────────────────

export async function getKycDocuments(userId: number) {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(kycDocuments).where(eq(kycDocuments.userId, userId)).orderBy(desc(kycDocuments.submittedAt));
}

export async function getPendingKyc(limit = 20) {
  const db = await getDb();
  if (!db) return [];
  return db.select({ doc: kycDocuments, user: users }).from(kycDocuments).innerJoin(users, eq(kycDocuments.userId, users.id)).where(eq(kycDocuments.status, "pending")).orderBy(desc(kycDocuments.submittedAt)).limit(limit);
}

// ─── SPORTSBOOK HELPERS ───────────────────────────────────────────────────────

export async function getSportEvents(sport?: string, status?: string) {
  const db = await getDb();
  if (!db) return [];
  const conditions = [];
  if (sport) conditions.push(eq(sportEvents.sport, sport));
  if (status) conditions.push(eq(sportEvents.status, status as any));
  else conditions.push(or(eq(sportEvents.status, "upcoming"), eq(sportEvents.status, "live")));
  return db.select().from(sportEvents).where(and(...conditions)).orderBy(sportEvents.startTime).limit(100);
}

export async function getUserBets(userId: number, limit = 20) {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(sportBets).where(eq(sportBets.userId, userId)).orderBy(desc(sportBets.createdAt)).limit(limit);
}

// ─── POKER HELPERS ────────────────────────────────────────────────────────────

export async function getPokerTables(currency?: string) {
  const db = await getDb();
  if (!db) return [];
  if (currency) return db.select().from(pokerTables).where(and(eq(pokerTables.currency, currency as any), sql`${pokerTables.status} != 'closed'`));
  return db.select().from(pokerTables).where(sql`${pokerTables.status} != 'closed'`);
}

export async function getPokerTournaments() {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(pokerTournaments).where(or(eq(pokerTournaments.status, "registering"), eq(pokerTournaments.status, "running"))).orderBy(pokerTournaments.startTime);
}

export async function getHandHistory(tableId: number, limit = 20) {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(pokerHands).where(eq(pokerHands.tableId, tableId)).orderBy(desc(pokerHands.createdAt)).limit(limit);
}

// ─── BINGO HELPERS ────────────────────────────────────────────────────────────

export async function getBingoRooms() {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(bingoRooms).where(sql`${bingoRooms.status} != 'paused'`);
}

export async function getUserBingoCards(userId: number, sessionId: number) {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(bingoCards).where(and(eq(bingoCards.userId, userId), eq(bingoCards.sessionId, sessionId)));
}

// ─── MINI-GAME HELPERS ────────────────────────────────────────────────────────

export async function getMiniGameHistory(userId: number, gameType?: string, limit = 20) {
  const db = await getDb();
  if (!db) return [];
  const conditions = [eq(miniGameRounds.userId, userId)];
  if (gameType) conditions.push(eq(miniGameRounds.gameType, gameType as any));
  return db.select().from(miniGameRounds).where(and(...conditions)).orderBy(desc(miniGameRounds.createdAt)).limit(limit);
}

// ─── SUPPORT TICKET HELPERS ───────────────────────────────────────────────────

export async function getTickets(userId?: number, status?: string, limit = 20) {
  const db = await getDb();
  if (!db) return [];
  const conditions = [];
  if (userId) conditions.push(eq(supportTickets.userId, userId));
  if (status) conditions.push(eq(supportTickets.status, status as any));
  const q = db.select().from(supportTickets).orderBy(desc(supportTickets.createdAt)).limit(limit);
  if (conditions.length > 0) return q.where(and(...conditions));
  return q;
}

export async function getTicketMessages(ticketId: number) {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(ticketMessages).where(eq(ticketMessages.ticketId, ticketId)).orderBy(ticketMessages.createdAt);
}

// ─── CHAT HELPERS ─────────────────────────────────────────────────────────────

export async function getChatMessages(channel = "global", limit = 50) {
  const db = await getDb();
  if (!db) return [];
  return db.select({ msg: chatMessages, user: { id: users.id, name: users.name, username: users.username, avatarUrl: users.avatarUrl } }).from(chatMessages).innerJoin(users, eq(chatMessages.userId, users.id)).where(and(eq(chatMessages.channel, channel), eq(chatMessages.isDeleted, false))).orderBy(desc(chatMessages.createdAt)).limit(limit);
}

// ─── FRAUD ALERT HELPERS ──────────────────────────────────────────────────────

export async function getFraudAlerts(status?: string, limit = 50) {
  const db = await getDb();
  if (!db) return [];
  const conditions = [];
  if (status) conditions.push(eq(fraudAlerts.status, status as any));
  const q = db.select({ alert: fraudAlerts, user: { id: users.id, name: users.name, username: users.username } }).from(fraudAlerts).innerJoin(users, eq(fraudAlerts.userId, users.id)).orderBy(desc(fraudAlerts.createdAt)).limit(limit);
  if (conditions.length > 0) return q.where(and(...conditions));
  return q;
}

// ─── ANALYTICS HELPERS ────────────────────────────────────────────────────────

export async function getAnalyticsSummary() {
  const db = await getDb();
  if (!db) return null;
  const [totalUsers] = await db.select({ count: sql<number>`COUNT(*)` }).from(users);
  const [totalTransactions] = await db.select({ count: sql<number>`COUNT(*)`, total: sql<number>`SUM(CAST(amount AS DECIMAL(18,2)))` }).from(transactions);
  const [activeToday] = await db.select({ count: sql<number>`COUNT(DISTINCT userId)` }).from(gameSessions).where(gte(gameSessions.createdAt, new Date(Date.now() - 86400000)));
  const [pendingKyc] = await db.select({ count: sql<number>`COUNT(*)` }).from(kycDocuments).where(eq(kycDocuments.status, "pending"));
  const [openAlerts] = await db.select({ count: sql<number>`COUNT(*)` }).from(fraudAlerts).where(eq(fraudAlerts.status, "open"));
  return { totalUsers: totalUsers.count, totalTransactions: totalTransactions.count, totalVolume: totalTransactions.total, activeToday: activeToday.count, pendingKyc: pendingKyc.count, openAlerts: openAlerts.count };
}

export async function getCoinPackages() {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(coinPackages).where(eq(coinPackages.isActive, true)).orderBy(coinPackages.sortOrder);
}

export async function getRestrictedStates() {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(restrictedStates).where(eq(restrictedStates.isActive, true));
}

export async function getStaffByUserId(userId: number) {
  const db = await getDb();
  if (!db) return undefined;
  const result = await db.select().from(staff).where(eq(staff.userId, userId)).limit(1);
  return result[0];
}

export async function getScRedemptions(userId?: number, status?: string) {
  const db = await getDb();
  if (!db) return [];
  const conditions = [];
  if (userId) conditions.push(eq(scRedemptions.userId, userId));
  if (status) conditions.push(eq(scRedemptions.status, status as any));
  const q = db.select().from(scRedemptions).orderBy(desc(scRedemptions.createdAt)).limit(50);
  if (conditions.length > 0) return q.where(and(...conditions));
  return q;
}


// ─── PLATFORM SETTINGS HELPERS ───────────────────────────────────────────────

export async function getPlatformSetting(key: string): Promise<string | null> {
  const db = await getDb();
  if (!db) return null;
  const rows = await db.select().from(platformSettings).where(eq(platformSettings.settingKey, key)).limit(1);
  return rows[0]?.settingValue ?? null;
}

export async function setPlatformSetting(key: string, value: string, updatedBy?: string): Promise<void> {
  const db = await getDb();
  if (!db) return;
  await db.insert(platformSettings).values({
    settingKey: key,
    settingValue: value,
    updatedBy: updatedBy ?? null,
  }).onDuplicateKeyUpdate({
    set: { settingValue: value, updatedBy: updatedBy ?? null },
  });
}

export async function getAllPlatformSettings(): Promise<Array<{ settingKey: string; settingValue: string; description: string | null; updatedAt: Date | null }>> {
  const db = await getDb();
  if (!db) return [];
  return db.select().from(platformSettings).orderBy(platformSettings.settingKey);
}


// Export db instance for direct access
export { getDb as db };
