import { router, protectedProcedure } from "../_core/trpc.ts";
import { z } from "zod";
import { getDb } from "../db.ts";
import { 
  adminShifts, 
  adminShiftAssignments, 
  adminShiftSwaps,
  users 
} from "../../drizzle/schema.ts";
import { eq, between, and } from "drizzle-orm";

export const adminShiftManagementRouter = router({
  // Get shifts for a date range
  getShifts: protectedProcedure
    .input(
      z.object({
        startDate: z.date(),
        endDate: z.date().optional(),
      })
    )
    .query(async ({ input }) => {
      const db = await getDb();
      const endDate = input.endDate || new Date(input.startDate.getTime() + 86400000);
      
      const shifts = await db
        .select()
        .from(adminShifts)
        .where(
          between(adminShifts.shiftDate, input.startDate, endDate)
        );

      // Get assignments for each shift
      const shiftsWithAssignments = await Promise.all(
        shifts.map(async (shift) => {
          const assignments = await db
            .select()
            .from(adminShiftAssignments)
            .where(eq(adminShiftAssignments.shiftId, shift.id));
          
          return {
            ...shift,
            assignedAdmins: assignments.map(a => a.adminId),
            coverage: assignments.length,
          };
        })
      );

      return shiftsWithAssignments;
    }),

  // Create a new shift
  createShift: protectedProcedure
    .input(
      z.object({
        name: z.string(),
        startTime: z.string(),
        endTime: z.string(),
        requiredCount: z.number().min(1),
        date: z.date(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      const result = await db.insert(adminShifts).values({
        name: input.name,
        startTime: input.startTime,
        endTime: input.endTime,
        requiredCount: input.requiredCount,
        shiftDate: input.date,
        createdBy: ctx.user?.id || 0,
      });

      return {
        id: result.insertId,
        ...input,
        assignedAdmins: [],
        coverage: 0,
        status: "open" as const,
      };
    }),

  // Get swap requests
  getSwapRequests: protectedProcedure.query(async () => {
    const db = await getDb();
    const swaps = await db
      .select()
      .from(adminShiftSwaps)
      .where(eq(adminShiftSwaps.status, "pending"));

    return swaps.map(swap => ({
      id: swap.id,
      requestedBy: swap.requestingAdminId,
      requestedWith: swap.requestingWithAdminId,
      fromShift: swap.fromShiftId,
      toShift: swap.toShiftId,
      status: swap.status as const,
      reason: swap.reason,
      createdAt: swap.requestedAt,
    }));
  }),

  // Get team members
  getTeamMembers: protectedProcedure.query(async () => {
    const db = await getDb();
    const admins = await db
      .select({
        id: users.id,
        name: users.username,
        role: users.role,
      })
      .from(users)
      .where(eq(users.role, "admin"));

    return admins.map(admin => ({
      id: admin.id,
      name: admin.name || "Unknown",
      role: admin.role || "admin",
      department: "Operations",
    }));
  }),

  // Approve shift swap
  approveShiftSwap: protectedProcedure
    .input(z.object({ swapId: z.number() }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      await db
        .update(adminShiftSwaps)
        .set({ status: "approved", respondedAt: new Date() })
        .where(eq(adminShiftSwaps.id, input.swapId));

      return { success: true };
    }),

  // Reject shift swap
  rejectShiftSwap: protectedProcedure
    .input(z.object({ swapId: z.number(), reason: z.string() }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      await db
        .update(adminShiftSwaps)
        .set({ 
          status: "rejected", 
          responseNotes: input.reason,
          respondedAt: new Date() 
        })
        .where(eq(adminShiftSwaps.id, input.swapId));

      return { success: true };
    }),

  // Assign admin to shift
  assignAdminToShift: protectedProcedure
    .input(
      z.object({
        shiftId: z.number(),
        adminId: z.number(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      const result = await db.insert(adminShiftAssignments).values({
        shiftId: input.shiftId,
        adminId: input.adminId,
        assignedBy: ctx.user?.id || 0,
      });

      return { success: true, assignmentId: result.insertId };
    }),

  // Remove admin from shift
  removeAdminFromShift: protectedProcedure
    .input(
      z.object({
        shiftId: z.number(),
        adminId: z.number(),
      })
    )
    .mutation(async ({ input }) => {
      const db = await getDb();
      await db
        .delete(adminShiftAssignments)
        .where(
          and(
            eq(adminShiftAssignments.shiftId, input.shiftId),
            eq(adminShiftAssignments.adminId, input.adminId)
          )
        );

      return { success: true };
    }),

  // Delete shift
  deleteShift: protectedProcedure
    .input(z.object({ shiftId: z.number() }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      // Delete assignments first
      await db
        .delete(adminShiftAssignments)
        .where(eq(adminShiftAssignments.shiftId, input.shiftId));

      // Then delete shift
      await db
        .delete(adminShifts)
        .where(eq(adminShifts.id, input.shiftId));

      return { success: true };
    }),

  // Get shift coverage analytics
  getShiftCoverageAnalytics: protectedProcedure.query(async () => {
    const db = await getDb();
    const allShifts = await db.select().from(adminShifts);
    const allAssignments = await db.select().from(adminShiftAssignments);

    const totalShifts = allShifts.length;
    const filledShifts = allShifts.filter(s => s.status === "filled").length;
    const openShifts = allShifts.filter(s => s.status === "open").length;
    const overfilledShifts = allShifts.filter(s => s.status === "overfilled").length;

    const coverageRate = totalShifts > 0 ? (filledShifts / totalShifts) * 100 : 0;

    return {
      totalShifts,
      filledShifts,
      openShifts,
      overfilledShifts,
      coverageRate: Math.round(coverageRate),
      totalAssignments: allAssignments.length,
      averageAssignmentsPerShift: totalShifts > 0 ? Math.round(allAssignments.length / totalShifts) : 0,
    };
  }),

  // Request shift swap
  requestShiftSwap: protectedProcedure
    .input(
      z.object({
        fromShiftId: z.number(),
        toShiftId: z.number(),
        requestingWithAdminId: z.number(),
        reason: z.string().optional(),
      })
    )
    .mutation(async ({ input, ctx }) => {
      const db = await getDb();
      const result = await db.insert(adminShiftSwaps).values({
        requestingAdminId: ctx.user?.id || 0,
        requestingWithAdminId: input.requestingWithAdminId,
        fromShiftId: input.fromShiftId,
        toShiftId: input.toShiftId,
        reason: input.reason,
      });

      return { success: true, swapId: result.insertId };
    }),

  // Get shift details
  getShiftDetails: protectedProcedure
    .input(z.object({ shiftId: z.number() }))
    .query(async ({ input }) => {
      const db = await getDb();
      const shift = await db
        .select()
        .from(adminShifts)
        .where(eq(adminShifts.id, input.shiftId));

      if (!shift.length) return null;

      const assignments = await db
        .select()
        .from(adminShiftAssignments)
        .where(eq(adminShiftAssignments.shiftId, input.shiftId));

      return {
        ...shift[0],
        assignments: assignments.map(a => ({
          id: a.id,
          adminId: a.adminId,
          status: a.status,
          assignedAt: a.assignedAt,
          confirmedAt: a.confirmedAt,
          completedAt: a.completedAt,
        })),
      };
    }),

  // Confirm shift assignment
  confirmShiftAssignment: protectedProcedure
    .input(z.object({ assignmentId: z.number() }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      await db
        .update(adminShiftAssignments)
        .set({ 
          status: "confirmed",
          confirmedAt: new Date()
        })
        .where(eq(adminShiftAssignments.id, input.assignmentId));

      return { success: true };
    }),

  // Complete shift assignment
  completeShiftAssignment: protectedProcedure
    .input(z.object({ assignmentId: z.number() }))
    .mutation(async ({ input }) => {
      const db = await getDb();
      await db
        .update(adminShiftAssignments)
        .set({ 
          status: "completed",
          completedAt: new Date()
        })
        .where(eq(adminShiftAssignments.id, input.assignmentId));

      return { success: true };
    }),
});
