import "server-only";
import { SportsPagePromotionStatus } from "@prisma/client";
import { z } from "zod";
import { prisma } from "@/server/db";
import { AppError } from "@/server/errors";

const relativeOrHttpUrlSchema = z
  .string()
  .trim()
  .min(1)
  .max(500)
  .refine((value) => value.startsWith("/") || value.startsWith("https://") || value.startsWith("http://"), {
    message: "URL relative ou https:// attendue"
  });

export const sportsPagePromotionInputSchema = z
  .object({
    id: z.string().uuid().optional(),
    title: z.string().trim().min(2).max(120),
    subtitle: z.string().trim().max(220).optional().nullable(),
    badge: z.string().trim().max(40).optional().nullable(),
    imageUrl: relativeOrHttpUrlSchema,
    href: relativeOrHttpUrlSchema,
    status: z.nativeEnum(SportsPagePromotionStatus).default(SportsPagePromotionStatus.ACTIVE),
    sortOrder: z.coerce.number().int().min(0).max(9999).default(100),
    startsAt: z.coerce.date().optional(),
    endsAt: z.coerce.date().nullable().optional()
  })
  .refine((value) => !value.endsAt || !value.startsAt || value.endsAt.getTime() > value.startsAt.getTime(), {
    message: "La date de fin doit être après le début.",
    path: ["endsAt"]
  });

export function serializeSportsPagePromotion(promotion: {
  id: string;
  title: string;
  subtitle: string | null;
  badge: string | null;
  imageUrl: string;
  href: string;
  status: SportsPagePromotionStatus;
  sortOrder: number;
  startsAt: Date;
  endsAt: Date | null;
  createdAt: Date;
  updatedAt: Date;
}) {
  return {
    id: promotion.id,
    title: promotion.title,
    subtitle: promotion.subtitle,
    badge: promotion.badge,
    imageUrl: promotion.imageUrl,
    href: promotion.href,
    status: promotion.status,
    sortOrder: promotion.sortOrder,
    startsAt: promotion.startsAt.toISOString(),
    endsAt: promotion.endsAt?.toISOString() ?? null,
    createdAt: promotion.createdAt.toISOString(),
    updatedAt: promotion.updatedAt.toISOString()
  };
}

export async function listAdminSportsPagePromotions() {
  const promotions = await prisma.sportsPagePromotion.findMany({
    where: { status: { not: SportsPagePromotionStatus.ARCHIVED } },
    orderBy: [{ sortOrder: "asc" }, { startsAt: "desc" }]
  });
  return promotions.map(serializeSportsPagePromotion);
}

export async function listActiveSportsPagePromotions(now = new Date()) {
  const promotions = await prisma.sportsPagePromotion.findMany({
    where: {
      status: SportsPagePromotionStatus.ACTIVE,
      startsAt: { lte: now },
      OR: [{ endsAt: null }, { endsAt: { gt: now } }]
    },
    orderBy: [{ sortOrder: "asc" }, { startsAt: "desc" }],
    take: 8
  });
  return promotions;
}

export async function upsertSportsPagePromotion(input: z.infer<typeof sportsPagePromotionInputSchema>) {
  const startsAt = input.startsAt ?? new Date();
  const data = {
    title: input.title,
    subtitle: input.subtitle?.trim() || null,
    badge: input.badge?.trim() || null,
    imageUrl: input.imageUrl,
    href: input.href,
    status: input.status,
    sortOrder: input.sortOrder,
    startsAt,
    endsAt: input.endsAt ?? null
  };

  const promotion = input.id
    ? await prisma.sportsPagePromotion.update({
        where: { id: input.id },
        data
      })
    : await prisma.sportsPagePromotion.create({ data });

  return serializeSportsPagePromotion(promotion);
}

export async function archiveSportsPagePromotion(id: string) {
  const result = await prisma.sportsPagePromotion.updateMany({
    where: { id },
    data: { status: SportsPagePromotionStatus.ARCHIVED }
  });

  if (result.count === 0) {
    throw new AppError("Promotion sport introuvable", 404, "SPORTS_PROMOTION_NOT_FOUND");
  }

  return { id };
}
