import { protectedProcedure, router } from "../_core/trpc.ts";
import { TRPCError } from "@trpc/server";
import { z } from "zod";
import {
  getAllUsers, getUserById, updateUser, getAuditLogs, getPendingKyc,
  getFraudAlerts, getAnalyticsSummary, writeAuditLog, getDb,
  creditWallet, debitWallet, getScRedemptions,
  getAllPlatformSettings, getPlatformSetting, setPlatformSetting
} from "../db.ts";
import { eq, desc, sql } from "drizzle-orm";
import { casinoGames, coinPackages, fraudAlerts, kycDocuments, platformSettings, rtpOverrides, scRedemptions, users, wallets } from "../../drizzle/schema.ts";

const adminProcedure = protectedProcedure.use(({ ctx, next }) => {
  if (ctx.user.role !== "admin") throw new TRPCError({ code: "FORBIDDEN", message: "Admin access required" });
  return next({ ctx });
});

export const adminRouter = router({
  // Analytics
  getDashboard: adminProcedure.query(async () => {
    return getAnalyticsSummary();
  }),

  getRevenueChart: adminProcedure
    .input(z.object({ days: z.number().min(1).max(90).default(30) }))
    .query(async ({ input }) => {
      const db = await getDb();
      if (!db) return [];
      const since = new Date(Date.now() - input.days * 86400000);
      const result = await db.execute(sql`
        SELECT DATE(createdAt) as date, 
               SUM(CASE WHEN type LIKE '%_bet' OR type = 'bingo_purchase' THEN CAST(amount AS DECIMAL) ELSE 0 END) as wagered,
               SUM(CASE WHEN type LIKE '%_win' THEN CAST(amount AS DECIMAL) ELSE 0 END) as paid_out,
               COUNT(DISTINCT userId) as unique_players
        FROM transactions 
        WHERE createdAt >= ${since}
        GROUP BY DATE(createdAt) 
        ORDER BY date ASC
      `);
      return (result[0] as unknown) as any[];
    }),

  // User Management
  getUsers: adminProcedure
    .input(z.object({ limit: z.number().default(50), offset: z.number().default(0), search: z.string().optional() }))
    .query(async ({ input }) => {
      return getAllUsers(input.limit, input.offset, input.search);
    }),

  getUser: adminProcedure
    .input(z.object({ userId: z.number() }))
    .query(async ({ input }) => {
      const user = await getUserById(input.userId);
      if (!user) throw new TRPCError({ code: "NOT_FOUND" });
      const db = await getDb();
      if (!db) return { user };
      const wallet = await db.select().from(wallets).where(eq(wallets.userId, input.userId)).limit(1);
      return { user, wallet: wallet[0] };
    }),

  banUser: adminProcedure
    .input(z.object({ userId: z.number(), reason: z.string().min(1) }))
    .mutation(async ({ ctx, input }) => {
      await updateUser(input.userId, { isBanned: true, banReason: input.reason });
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", targetUserId: input.userId, action: "user_banned", category: "admin", details: { reason: input.reason } });
      return { success: true };
    }),

  unbanUser: adminProcedure
    .input(z.object({ userId: z.number() }))
    .mutation(async ({ ctx, input }) => {
      await updateUser(input.userId, { isBanned: false, banReason: null });
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", targetUserId: input.userId, action: "user_unbanned", category: "admin" });
      return { success: true };
    }),

  adjustBalance: adminProcedure
    .input(z.object({
      userId: z.number(),
      currency: z.enum(["GC", "SC"]),
      amount: z.number(),
      reason: z.string().min(1),
    }))
    .mutation(async ({ ctx, input }) => {
      if (input.amount > 0) {
        await creditWallet(input.userId, input.currency, input.amount, "admin_credit", `Admin credit: ${input.reason}`, String(ctx.user.id));
      } else {
        await debitWallet(input.userId, input.currency, Math.abs(input.amount), "admin_debit", `Admin debit: ${input.reason}`, String(ctx.user.id));
      }
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", targetUserId: input.userId, action: "balance_adjusted", category: "admin", details: { currency: input.currency, amount: input.amount, reason: input.reason } });
      return { success: true };
    }),

  promoteToAdmin: adminProcedure
    .input(z.object({ userId: z.number() }))
    .mutation(async ({ ctx, input }) => {
      await updateUser(input.userId, { role: "admin" });
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", targetUserId: input.userId, action: "user_promoted_admin", category: "admin" });
      return { success: true };
    }),

  // KYC Management
  getPendingKyc: adminProcedure.query(async () => {
    return getPendingKyc(50);
  }),

  reviewKyc: adminProcedure
    .input(z.object({
      docId: z.number(),
      userId: z.number(),
      status: z.enum(["approved", "rejected"]),
      note: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.update(kycDocuments).set({ status: input.status, reviewedBy: ctx.user.id, reviewNote: input.note ?? null, reviewedAt: new Date() }).where(eq(kycDocuments.id, input.docId));

      // Check if all docs approved
      const allDocs = await db.select().from(kycDocuments).where(eq(kycDocuments.userId, input.userId));
      const allApproved = allDocs.length > 0 && allDocs.every(d => d.status === "approved");
      if (allApproved) {
        await updateUser(input.userId, { kycStatus: "approved", kycLevel: 1 });
      } else if (input.status === "rejected") {
        await updateUser(input.userId, { kycStatus: "rejected" });
      }

      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", targetUserId: input.userId, action: `kyc_${input.status}`, category: "kyc", details: { docId: input.docId, note: input.note } });
      return { success: true };
    }),

  // RTP Management
  setRtpOverride: adminProcedure
    .input(z.object({
      userId: z.number().optional(),
      gameId: z.number().optional(),
      rtpOverride: z.number().min(50).max(99),
      reason: z.string().min(1),
      expiresAt: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.insert(rtpOverrides).values({
        userId: input.userId ?? null,
        gameId: input.gameId ?? null,
        rtpOverride: input.rtpOverride,
        setByAdminId: ctx.user.id,
        reason: input.reason,
        expiresAt: input.expiresAt ? new Date(input.expiresAt) : null,
      });
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", targetUserId: input.userId, action: "rtp_override_set", category: "admin", details: input });
      return { success: true };
    }),

  getRtpOverrides: adminProcedure.query(async () => {
    const db = await getDb();
    if (!db) return [];
    return db.select().from(rtpOverrides).orderBy(desc(rtpOverrides.createdAt)).limit(100);
  }),

  // ─── Coin Package Management (Full CRUD) ────────────────────────────────────
  getCoinPackages: adminProcedure.query(async () => {
    const db = await getDb();
    if (!db) return [];
    return db.select().from(coinPackages).orderBy(coinPackages.sortOrder);
  }),

  createCoinPackage: adminProcedure
    .input(z.object({
      name: z.string().min(1),
      gcAmount: z.number().min(1),
      scBonusAmount: z.number().min(0).default(0),
      priceUsd: z.number().min(0.50),
      isPopular: z.boolean().default(false),
      isBestValue: z.boolean().default(false),
      isActive: z.boolean().default(true),
      sortOrder: z.number().default(0),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.insert(coinPackages).values({
        name: input.name,
        gcAmount: input.gcAmount.toFixed(2),
        scBonusAmount: input.scBonusAmount.toFixed(2),
        priceUsd: input.priceUsd.toFixed(2),
        isPopular: input.isPopular,
        isBestValue: input.isBestValue,
        isActive: input.isActive,
        sortOrder: input.sortOrder,
      });
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "coin_package_created", category: "admin", details: input });
      return { success: true };
    }),

  updateCoinPackage: adminProcedure
    .input(z.object({
      id: z.number(),
      name: z.string().optional(),
      gcAmount: z.number().optional(),
      scBonusAmount: z.number().optional(),
      priceUsd: z.number().optional(),
      isActive: z.boolean().optional(),
      isPopular: z.boolean().optional(),
      isBestValue: z.boolean().optional(),
      sortOrder: z.number().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      const { id, ...updates } = input;
      const updateData: Record<string, unknown> = {};
      if (updates.name !== undefined) updateData.name = updates.name;
      if (updates.gcAmount !== undefined) updateData.gcAmount = updates.gcAmount.toFixed(2);
      if (updates.scBonusAmount !== undefined) updateData.scBonusAmount = updates.scBonusAmount.toFixed(2);
      if (updates.priceUsd !== undefined) updateData.priceUsd = updates.priceUsd.toFixed(2);
      if (updates.isActive !== undefined) updateData.isActive = updates.isActive;
      if (updates.isPopular !== undefined) updateData.isPopular = updates.isPopular;
      if (updates.isBestValue !== undefined) updateData.isBestValue = updates.isBestValue;
      if (updates.sortOrder !== undefined) updateData.sortOrder = updates.sortOrder;
      await db.update(coinPackages).set(updateData).where(eq(coinPackages.id, id));
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "coin_package_updated", category: "admin", details: input });
      return { success: true };
    }),

  deleteCoinPackage: adminProcedure
    .input(z.object({ id: z.number() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.delete(coinPackages).where(eq(coinPackages.id, input.id));
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "coin_package_deleted", category: "admin", details: { id: input.id } });
      return { success: true };
    }),

  reorderCoinPackages: adminProcedure
    .input(z.object({ orderedIds: z.array(z.number()) }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      for (let i = 0; i < input.orderedIds.length; i++) {
        await db.update(coinPackages).set({ sortOrder: i + 1 }).where(eq(coinPackages.id, input.orderedIds[i]));
      }
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "coin_packages_reordered", category: "admin", details: { orderedIds: input.orderedIds } });
      return { success: true };
    }),

  // ─── Game Management (Full CRUD) ────────────────────────────────────────────
  getAllGamesAdmin: adminProcedure
    .input(z.object({
      limit: z.number().min(1).max(200).default(50),
      offset: z.number().min(0).default(0),
      search: z.string().optional(),
      category: z.string().optional(),
      provider: z.string().optional(),
      isActive: z.boolean().optional(),
    }).optional())
    .query(async ({ input }) => {
      const db = await getDb();
      if (!db) return { games: [], total: 0 };
      const { limit = 50, offset = 0, search, category, provider, isActive } = input || {};
      const conditions: any[] = [];
      if (search) conditions.push(sql`${casinoGames.title} LIKE ${'%' + search + '%'}`);
      if (category && category !== 'all') conditions.push(eq(casinoGames.category, category as any));
      if (provider && provider !== 'all') conditions.push(eq(casinoGames.provider, provider));
      if (isActive !== undefined) conditions.push(eq(casinoGames.isActive, isActive));
      const whereClause = conditions.length > 0 ? sql`${sql.join(conditions, sql` AND `)}` : undefined;
      const [countResult] = await db.select({ count: sql<number>`COUNT(*)` }).from(casinoGames).where(whereClause as any);
      const games = await db.select().from(casinoGames).where(whereClause as any).orderBy(desc(casinoGames.playCount)).limit(limit).offset(offset);
      return { games, total: countResult.count };
    }),

  updateGame: adminProcedure
    .input(z.object({
      gameId: z.number(),
      title: z.string().optional(),
      provider: z.string().optional(),
      category: z.enum(["slots", "table", "live", "jackpot", "new", "popular", "crash", "instant"]).optional(),
      rtp: z.number().min(50).max(99.9).optional(),
      volatility: z.enum(["low", "medium", "high", "very_high"]).optional(),
      minBetGc: z.number().min(0).optional(),
      maxBetGc: z.number().min(0).optional(),
      minBetSc: z.number().min(0).optional(),
      maxBetSc: z.number().min(0).optional(),
      isActive: z.boolean().optional(),
      isFeatured: z.boolean().optional(),
      isNew: z.boolean().optional(),
      description: z.string().optional(),
      paylines: z.number().optional(),
      reels: z.number().optional(),
      features: z.array(z.string()).optional(),
      thumbnailUrl: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      const { gameId, ...updates } = input;
      const updateData: Record<string, unknown> = {};
      if (updates.title !== undefined) updateData.title = updates.title;
      if (updates.provider !== undefined) updateData.provider = updates.provider;
      if (updates.category !== undefined) updateData.category = updates.category;
      if (updates.rtp !== undefined) updateData.rtp = updates.rtp;
      if (updates.volatility !== undefined) updateData.volatility = updates.volatility;
      if (updates.minBetGc !== undefined) updateData.minBetGc = updates.minBetGc.toFixed(2);
      if (updates.maxBetGc !== undefined) updateData.maxBetGc = updates.maxBetGc.toFixed(2);
      if (updates.minBetSc !== undefined) updateData.minBetSc = updates.minBetSc.toFixed(2);
      if (updates.maxBetSc !== undefined) updateData.maxBetSc = updates.maxBetSc.toFixed(2);
      if (updates.isActive !== undefined) updateData.isActive = updates.isActive;
      if (updates.isFeatured !== undefined) updateData.isFeatured = updates.isFeatured;
      if (updates.isNew !== undefined) updateData.isNew = updates.isNew;
      if (updates.description !== undefined) updateData.description = updates.description;
      if (updates.paylines !== undefined) updateData.paylines = updates.paylines;
      if (updates.reels !== undefined) updateData.reels = updates.reels;
      if (updates.features !== undefined) updateData.features = JSON.stringify(updates.features);
      if (updates.thumbnailUrl !== undefined) updateData.thumbnailUrl = updates.thumbnailUrl;
      await db.update(casinoGames).set(updateData).where(eq(casinoGames.id, gameId));
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "game_updated", category: "admin", details: input });
      return { success: true };
    }),

  createGame: adminProcedure
    .input(z.object({
      title: z.string().min(1),
      provider: z.string().min(1),
      category: z.enum(["slots", "table", "live", "jackpot", "new", "popular", "crash", "instant"]),
      rtp: z.number().min(50).max(99.9).default(96),
      volatility: z.enum(["low", "medium", "high", "very_high"]).default("medium"),
      minBetGc: z.number().default(1),
      maxBetGc: z.number().default(1000),
      minBetSc: z.number().default(0.01),
      maxBetSc: z.number().default(20),
      description: z.string().optional(),
      paylines: z.number().default(25),
      reels: z.number().default(5),
      features: z.array(z.string()).optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      const slug = input.title.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/-+$/, "");
      await db.insert(casinoGames).values({
        slug,
        title: input.title,
        provider: input.provider,
        category: input.category,
        rtp: input.rtp,
        volatility: input.volatility,
        minBetGc: input.minBetGc.toFixed(2),
        maxBetGc: input.maxBetGc.toFixed(2),
        minBetSc: input.minBetSc.toFixed(2),
        maxBetSc: input.maxBetSc.toFixed(2),
        isActive: 1,
        isFeatured: 0,
        isNew: 1,
        description: input.description || null,
        paylines: input.paylines,
        reels: input.reels,
        features: input.features ? JSON.stringify(input.features) : null,
      } as any);
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "game_created", category: "admin", details: input });
      return { success: true };
    }),

  deleteGame: adminProcedure
    .input(z.object({ gameId: z.number() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.delete(casinoGames).where(eq(casinoGames.id, input.gameId));
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "game_deleted", category: "admin", details: { gameId: input.gameId } });
      return { success: true };
    }),

  bulkToggleGames: adminProcedure
    .input(z.object({ gameIds: z.array(z.number()), isActive: z.boolean() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      for (const id of input.gameIds) {
        await db.update(casinoGames).set({ isActive: input.isActive }).where(eq(casinoGames.id, id));
      }
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: `bulk_games_${input.isActive ? 'enabled' : 'disabled'}`, category: "admin", details: { count: input.gameIds.length } });
      return { success: true };
    }),

  toggleGame: adminProcedure
    .input(z.object({ gameId: z.number(), isActive: z.boolean() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.update(casinoGames).set({ isActive: input.isActive }).where(eq(casinoGames.id, input.gameId));
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: `game_${input.isActive ? "enabled" : "disabled"}`, category: "admin", details: { gameId: input.gameId } });
      return { success: true };
    }),

  // Audit Logs
  getAuditLogs: adminProcedure
    .input(z.object({ limit: z.number().default(50), offset: z.number().default(0), category: z.string().optional(), userId: z.number().optional() }))
    .query(async ({ input }) => {
      return getAuditLogs(input.limit, input.offset, input.category, input.userId);
    }),

  // Fraud Alerts
  getFraudAlerts: adminProcedure
    .input(z.object({ status: z.string().optional() }))
    .query(async ({ input }) => {
      return getFraudAlerts(input.status);
    }),

  resolveFraudAlert: adminProcedure
    .input(z.object({ alertId: z.number(), status: z.enum(["resolved", "dismissed", "investigating"]) }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.update(fraudAlerts).set({ status: input.status, resolvedBy: ctx.user.id, resolvedAt: new Date() }).where(eq(fraudAlerts.id, input.alertId));
      return { success: true };
    }),

  // SC Redemptions
  getRedemptions: adminProcedure
    .input(z.object({ status: z.string().optional() }))
    .query(async ({ input }) => {
      return getScRedemptions(undefined, input.status);
    }),

  processRedemption: adminProcedure
    .input(z.object({
      redemptionId: z.number(),
      status: z.enum(["approved", "processing", "completed", "rejected"]),
      note: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.update(scRedemptions).set({ status: input.status, reviewedBy: ctx.user.id, reviewNote: input.note ?? null, processedAt: new Date() }).where(eq(scRedemptions.id, input.redemptionId));
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: `redemption_${input.status}`, category: "admin", details: { redemptionId: input.redemptionId } });
      return { success: true };
    }),

  // ─── MAKE IT RAIN ────────────────────────────────────────────────────────────
  makeItRain: adminProcedure
    .input(z.object({
      target: z.enum(["all", "single"]),
      userId: z.number().optional(),
      amount: z.number().min(0.01).max(100000),
      currency: z.enum(["GC", "SC"]),
      reason: z.string().min(1).max(500),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      let credited = 0;
      if (input.target === "single") {
        if (!input.userId) throw new TRPCError({ code: "BAD_REQUEST", message: "User ID required for single target" });
        await creditWallet(input.userId, input.currency, input.amount, "admin_bonus", `Make It Rain: ${input.reason}`, "make_it_rain", "admin_action");
        credited = 1;
      } else {
        const allUsers = await db.select({ id: users.id }).from(users).where(eq(users.isBanned, false));
        for (const u of allUsers) {
          try {
            await creditWallet(u.id, input.currency, input.amount, "admin_bonus", `Make It Rain: ${input.reason}`, "make_it_rain", "admin_action");
            credited++;
          } catch (e) { /* skip failed users */ }
        }
      }
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "make_it_rain", category: "admin", details: { target: input.target, userId: input.userId, amount: input.amount, currency: input.currency, reason: input.reason, usersCredited: credited } });
      return { success: true, usersCredited: credited };
    }),

  // ─── PAYMENT METHODS ─────────────────────────────────────────────────────────
  getPaymentMethods: adminProcedure.query(async () => {
    const db = await getDb();
    if (!db) return [];
    const result = await db.execute(sql`SELECT * FROM payment_methods ORDER BY sortOrder ASC`);
    return (result[0] as unknown) as any[];
  }),

  createPaymentMethod: adminProcedure
    .input(z.object({
      name: z.string().min(1),
      provider: z.string().min(1),
      type: z.enum(["purchase", "redemption"]),
      feePercent: z.number().min(0).max(100).default(0),
      flatFee: z.number().min(0).default(0),
      minAmount: z.number().min(0).default(0),
      maxAmount: z.number().min(0).default(10000),
      isEnabled: z.boolean().default(true),
      iconUrl: z.string().optional(),
      description: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.execute(sql`INSERT INTO payment_methods (name, provider, type, feePercent, flatFee, minAmount, maxAmount, isEnabled, iconUrl, description, sortOrder) VALUES (${input.name}, ${input.provider}, ${input.type}, ${input.feePercent}, ${input.flatFee}, ${input.minAmount}, ${input.maxAmount}, ${input.isEnabled}, ${input.iconUrl ?? null}, ${input.description ?? null}, (SELECT COALESCE(MAX(s.sortOrder), 0) + 1 FROM payment_methods s))`);
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "create_payment_method", category: "admin", details: input });
      return { success: true };
    }),

  updatePaymentMethod: adminProcedure
    .input(z.object({
      id: z.number(),
      name: z.string().optional(),
      provider: z.string().optional(),
      feePercent: z.number().min(0).max(100).optional(),
      flatFee: z.number().min(0).optional(),
      minAmount: z.number().min(0).optional(),
      maxAmount: z.number().min(0).optional(),
      isEnabled: z.boolean().optional(),
      iconUrl: z.string().optional(),
      description: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      const { id, ...updates } = input;
      const setClauses = Object.entries(updates).filter(([, v]) => v !== undefined).map(([k, v]) => `${k} = ${typeof v === "string" ? `'${v.replace(/'/g, "''")}'` : v}`).join(", ");
      if (setClauses) await db.execute(sql.raw(`UPDATE payment_methods SET ${setClauses} WHERE id = ${id}`));
      return { success: true };
    }),

  deletePaymentMethod: adminProcedure
    .input(z.object({ id: z.number() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.execute(sql`DELETE FROM payment_methods WHERE id = ${input.id}`);
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "delete_payment_method", category: "admin", details: { id: input.id } });
      return { success: true };
    }),

  // ─── AI EMPLOYEES ────────────────────────────────────────────────────────────
  getAIEmployees: adminProcedure.query(async () => {
    const db = await getDb();
    if (!db) return [];
    const result = await db.execute(sql`SELECT * FROM ai_employees ORDER BY createdAt DESC`);
    return (result[0] as unknown) as any[];
  }),

  createAIEmployee: adminProcedure
    .input(z.object({
      name: z.string().min(1),
      role: z.string().min(1),
      department: z.string().min(1),
      systemPrompt: z.string().optional(),
      avatarUrl: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.execute(sql`INSERT INTO ai_employees (name, role, department, systemPrompt, avatarUrl, isActive) VALUES (${input.name}, ${input.role}, ${input.department}, ${input.systemPrompt ?? "You are a helpful AI assistant."}, ${input.avatarUrl ?? null}, true)`);
      await writeAuditLog({ actorId: ctx.user.id, actorRole: "admin", action: "create_ai_employee", category: "admin", details: input });
      return { success: true };
    }),

  deleteAIEmployee: adminProcedure
    .input(z.object({ id: z.number() }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.execute(sql`DELETE FROM ai_employees WHERE id = ${input.id}`);
      return { success: true };
    }),

  toggleAIEmployee: adminProcedure
    .input(z.object({ id: z.number(), isActive: z.boolean() }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.execute(sql`UPDATE ai_employees SET isActive = ${input.isActive} WHERE id = ${input.id}`);
      return { success: true };
    }),

  chatWithAIEmployee: adminProcedure
    .input(z.object({
      employeeId: z.number(),
      message: z.string().min(1),
      conversationHistory: z.array(z.object({ role: z.enum(["user", "assistant"]), content: z.string() })).optional(),
    }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      const employees = await db.execute(sql`SELECT * FROM ai_employees WHERE id = ${input.employeeId}`);
      const employee = (employees[0] as any)?.[0];
      if (!employee) throw new TRPCError({ code: "NOT_FOUND", message: "AI Employee not found" });
      const { invokeLLM } = await import("../_core/llm");
      const messages: any[] = [
        { role: "system", content: employee.systemPrompt || `You are ${employee.name}, a ${employee.role} in the ${employee.department} department at CoinKrazy sweepstakes casino. Be helpful, professional, and knowledgeable about casino operations.` },
        ...(input.conversationHistory || []),
        { role: "user", content: input.message },
      ];
      const response = await invokeLLM({ messages });
      const reply = response.choices?.[0]?.message?.content || "I apologize, I'm unable to respond right now.";
      // Save chat message
      await db.execute(sql`INSERT INTO ai_employee_chats (employeeId, userMessage, assistantMessage) VALUES (${input.employeeId}, ${input.message}, ${reply})`);
      return { reply };
    }),

  getAIEmployeeChats: adminProcedure
    .input(z.object({ employeeId: z.number(), limit: z.number().default(50) }))
    .query(async ({ input }) => {
      const db = await getDb();
      if (!db) return [];
      const result = await db.execute(sql`SELECT * FROM ai_employee_chats WHERE employeeId = ${input.employeeId} ORDER BY createdAt DESC LIMIT ${input.limit}`);
      return (result[0] as unknown) as any[];
    }),

  // ─── AI TASKS ────────────────────────────────────────────────────────────────
  getAITasks: adminProcedure.query(async () => {
    const db = await getDb();
    if (!db) return [];
    const result = await db.execute(sql`SELECT t.*, e.name as employeeName FROM ai_employee_tasks t LEFT JOIN ai_employees e ON t.assignedTo = e.id ORDER BY t.createdAt DESC`);
    return (result[0] as unknown) as any[];
  }),

  createAITask: adminProcedure
    .input(z.object({
      title: z.string().min(1),
      description: z.string().min(1),
      assignedTo: z.number(),
      priority: z.enum(["low", "medium", "high", "urgent"]).default("medium"),
      dueDate: z.string().optional(),
    }))
    .mutation(async ({ ctx, input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.execute(sql`INSERT INTO ai_employee_tasks (title, description, assignedTo, priority, dueDate, status) VALUES (${input.title}, ${input.description}, ${input.assignedTo}, ${input.priority}, ${input.dueDate ?? null}, 'pending')`);
      return { success: true };
    }),

  updateAITaskStatus: adminProcedure
    .input(z.object({ taskId: z.number(), status: z.enum(["pending", "in_progress", "completed", "cancelled"]) }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      if (!db) throw new Error("DB unavailable");
      await db.execute(sql`UPDATE ai_employee_tasks SET status = ${input.status}, updatedAt = NOW() WHERE id = ${input.taskId}`);
      return { success: true };
    }),

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

  getPlatformSettings: adminProcedure.query(async () => {
    return getAllPlatformSettings();
  }),

  updatePlatformSetting: adminProcedure
    .input(z.object({
      key: z.string(),
      value: z.string(),
    }))
    .mutation(async ({ ctx, input }) => {
      await setPlatformSetting(input.key, input.value, ctx.user.name ?? ctx.user.openId);
      await writeAuditLog({
        actorId: ctx.user.id,
        actorRole: "admin",
        action: "update_platform_setting",
        category: "admin",
        details: `Updated ${input.key} to ${input.value}`,
        ipAddress: "admin",
      });
      return { success: true };
    }),
});
