import { router, protectedProcedure } from '@/src/trpc/trpc-index'
import { z } from 'zod';
import { db } from '@/src/db/db_index'
import { productAvailabilitySchedules } from '@/src/db/schema'
import { eq } from 'drizzle-orm';
import { refreshScheduleJobs } from '@/src/lib/automatedJobs';

const createScheduleSchema = z.object({
  scheduleName: z.string().min(1, "Schedule name is required"),
  time: z.string().min(1, "Time is required").regex(/^([01]?[0-9]|2[0-3]):[0-5][0-9]$/, "Invalid time format. Use HH:MM"),
  action: z.enum(['in', 'out']),
  productIds: z.array(z.number().int().positive()).min(1, "At least one product is required"),
  groupIds: z.array(z.number().int().positive()).default([]),
});

const updateScheduleSchema = z.object({
  id: z.number().int().positive(),
  updates: createScheduleSchema.partial().extend({
    scheduleName: z.string().min(1).optional(),
    productIds: z.array(z.number().int().positive()).optional(),
    groupIds: z.array(z.number().int().positive()).optional(),
  }),
});

export const productAvailabilitySchedulesRouter = router({
  create: protectedProcedure
    .input(createScheduleSchema)
    .mutation(async ({ input, ctx }) => {
      const { scheduleName, time, action, productIds, groupIds } = input;

      // Get staff user ID from auth middleware
      const staffUserId = ctx.staffUser?.id;
      if (!staffUserId) {
        throw new Error("Unauthorized");
      }

      // Check if schedule name already exists
      const existingSchedule = await db.query.productAvailabilitySchedules.findFirst({
        where: eq(productAvailabilitySchedules.scheduleName, scheduleName),
      });
      if (existingSchedule) {
        throw new Error("Schedule name already exists");
      }

      // Create schedule with arrays
      const scheduleResult = await db.insert(productAvailabilitySchedules).values({
        scheduleName,
        time,
        action,
        productIds,
        groupIds,
      }).returning();

      // Refresh cron jobs to include new schedule
      await refreshScheduleJobs();

      return scheduleResult[0];
    }),

  getAll: protectedProcedure
    .query(async () => {
      const schedules = await db.query.productAvailabilitySchedules.findMany({
        orderBy: (productAvailabilitySchedules, { desc }) => [desc(productAvailabilitySchedules.createdAt)],
      });

      return schedules.map(schedule => ({
        ...schedule,
        productCount: schedule.productIds.length,
        groupCount: schedule.groupIds.length,
      }));
    }),

  getById: protectedProcedure
    .input(z.object({ id: z.number().int().positive() }))
    .query(async ({ input }) => {
      const { id } = input;

      const schedule = await db.query.productAvailabilitySchedules.findFirst({
        where: eq(productAvailabilitySchedules.id, id),
      });

      if (!schedule) {
        throw new Error("Schedule not found");
      }

      return schedule;
    }),

  update: protectedProcedure
    .input(updateScheduleSchema)
    .mutation(async ({ input }) => {
      const { id, updates } = input;

      // Check if schedule exists
      const existingSchedule = await db.query.productAvailabilitySchedules.findFirst({
        where: eq(productAvailabilitySchedules.id, id),
      });
      if (!existingSchedule) {
        throw new Error("Schedule not found");
      }

      // Check schedule name uniqueness if being updated
      if (updates.scheduleName && updates.scheduleName !== existingSchedule.scheduleName) {
        const duplicateSchedule = await db.query.productAvailabilitySchedules.findFirst({
          where: eq(productAvailabilitySchedules.scheduleName, updates.scheduleName),
        });
        if (duplicateSchedule) {
          throw new Error("Schedule name already exists");
        }
      }

      // Update schedule
      const updateData: any = {};
      if (updates.scheduleName !== undefined) updateData.scheduleName = updates.scheduleName;
      if (updates.time !== undefined) updateData.time = updates.time;
      if (updates.action !== undefined) updateData.action = updates.action;
      if (updates.productIds !== undefined) updateData.productIds = updates.productIds;
      if (updates.groupIds !== undefined) updateData.groupIds = updates.groupIds;
      updateData.lastUpdated = new Date();

      const result = await db.update(productAvailabilitySchedules)
        .set(updateData)
        .where(eq(productAvailabilitySchedules.id, id))
        .returning();

      if (result.length === 0) {
        throw new Error("Failed to update schedule");
      }

      // Refresh cron jobs to reflect changes
      await refreshScheduleJobs();

      return result[0];
    }),

  delete: protectedProcedure
    .input(z.object({ id: z.number().int().positive() }))
    .mutation(async ({ input }) => {
      const { id } = input;

      const result = await db.delete(productAvailabilitySchedules)
        .where(eq(productAvailabilitySchedules.id, id))
        .returning();

      if (result.length === 0) {
        throw new Error("Schedule not found");
      }

      // Refresh cron jobs to remove deleted schedule
      await refreshScheduleJobs();

      return { message: "Schedule deleted successfully" };
    }),
});
