import { z } from "zod";
import { router, protectedProcedure, publicProcedure } from "../_core/trpc.ts";
import { TRPCError } from "@trpc/server";
import { getDb } from "../db.ts";
import { promoBanners } from "../../drizzle/schema.ts";
import { eq, and, lte, gte, asc, desc, isNull, or } from "drizzle-orm";

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

export const promoBannersRouter = router({
  // Public: get active banners for homepage carousel
  getActive: publicProcedure.query(async () => {
    const now = new Date();
    const database = await getDb();
    if (!database) throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Database unavailable" });
    const banners = await database
      .select()
      .from(promoBanners)
      .where(eq(promoBanners.isActive, true))
      .orderBy(asc(promoBanners.sortOrder));

    // Filter by date range (startAt/endAt) in JS since SQL timestamp comparisons can be tricky
    return banners.filter((b: typeof banners[number]) => {
      if (b.startAt && new Date(b.startAt) > now) return false;
      if (b.endAt && new Date(b.endAt) < now) return false;
      return true;
    });
  }),

  // Admin: get all banners (including inactive)
  getAll: adminProcedure.query(async () => {
    const database = await getDb();
    if (!database) throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Database unavailable" });
    const banners = await database
      .select()
      .from(promoBanners)
      .orderBy(asc(promoBanners.sortOrder));
    return banners;
  }),

  // Admin: create a new banner
  create: adminProcedure
    .input(
      z.object({
        title: z.string().min(1).max(255),
        subtitle: z.string().optional(),
        description: z.string().optional(),
        imageUrl: z.string().optional(),
        linkUrl: z.string().optional(),
        linkText: z.string().max(128).optional(),
        bgGradientFrom: z.string().max(32).optional(),
        bgGradientTo: z.string().max(32).optional(),
        textColor: z.string().max(32).optional(),
        sortOrder: z.number().int().optional(),
        isActive: z.boolean().optional(),
        startAt: z.string().optional(),
        endAt: z.string().optional(),
      })
    )
    .mutation(async ({ ctx, input }) => {
      const database = await getDb();
      if (!database) throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Database unavailable" });
      const result = await database.insert(promoBanners).values({
        title: input.title,
        subtitle: input.subtitle || null,
        description: input.description || null,
        imageUrl: input.imageUrl || null,
        linkUrl: input.linkUrl || null,
        linkText: input.linkText || null,
        bgGradientFrom: input.bgGradientFrom || "#f59e0b",
        bgGradientTo: input.bgGradientTo || "#d97706",
        textColor: input.textColor || "#ffffff",
        sortOrder: input.sortOrder ?? 0,
        isActive: input.isActive ?? true,
        startAt: input.startAt ? new Date(input.startAt) : null,
        endAt: input.endAt ? new Date(input.endAt) : null,
        createdByAdminId: ctx.user.id,
      });
      return { success: true, id: Number(result[0].insertId) };
    }),

  // Admin: update a banner
  update: adminProcedure
    .input(
      z.object({
        id: z.number().int(),
        title: z.string().min(1).max(255).optional(),
        subtitle: z.string().optional(),
        description: z.string().optional(),
        imageUrl: z.string().optional(),
        linkUrl: z.string().optional(),
        linkText: z.string().max(128).optional(),
        bgGradientFrom: z.string().max(32).optional(),
        bgGradientTo: z.string().max(32).optional(),
        textColor: z.string().max(32).optional(),
        sortOrder: z.number().int().optional(),
        isActive: z.boolean().optional(),
        startAt: z.string().nullable().optional(),
        endAt: z.string().nullable().optional(),
      })
    )
    .mutation(async ({ input }) => {
      const updateData: Record<string, unknown> = {};
      if (input.title !== undefined) updateData.title = input.title;
      if (input.subtitle !== undefined) updateData.subtitle = input.subtitle;
      if (input.description !== undefined) updateData.description = input.description;
      if (input.imageUrl !== undefined) updateData.imageUrl = input.imageUrl;
      if (input.linkUrl !== undefined) updateData.linkUrl = input.linkUrl;
      if (input.linkText !== undefined) updateData.linkText = input.linkText;
      if (input.bgGradientFrom !== undefined) updateData.bgGradientFrom = input.bgGradientFrom;
      if (input.bgGradientTo !== undefined) updateData.bgGradientTo = input.bgGradientTo;
      if (input.textColor !== undefined) updateData.textColor = input.textColor;
      if (input.sortOrder !== undefined) updateData.sortOrder = input.sortOrder;
      if (input.isActive !== undefined) updateData.isActive = input.isActive;
      if (input.startAt !== undefined) updateData.startAt = input.startAt ? new Date(input.startAt) : null;
      if (input.endAt !== undefined) updateData.endAt = input.endAt ? new Date(input.endAt) : null;

      const database = await getDb();
      if (!database) throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Database unavailable" });
      await database
        .update(promoBanners)
        .set(updateData)
        .where(eq(promoBanners.id, input.id));
      return { success: true };
    }),

  // Admin: delete a banner
  delete: adminProcedure
    .input(z.object({ id: z.number().int() }))
    .mutation(async ({ input }) => {
      const database = await getDb();
      if (!database) throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Database unavailable" });
      await database.delete(promoBanners).where(eq(promoBanners.id, input.id));
      return { success: true };
    }),

  // Admin: reorder banners
  reorder: adminProcedure
    .input(
      z.object({
        orderedIds: z.array(z.number().int()),
      })
    )
    .mutation(async ({ input }) => {
      const database = await getDb();
      if (!database) throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Database unavailable" });
      for (let i = 0; i < input.orderedIds.length; i++) {
        await database
          .update(promoBanners)
          .set({ sortOrder: i })
          .where(eq(promoBanners.id, input.orderedIds[i]));
      }
      return { success: true };
    }),
});
