import { prisma } from "@/lib/prisma";
import { Prisma } from "@/app/generated/prisma/client";
import type { ActivityCategory, Vibe } from "@/app/generated/prisma/enums";
import {
  utcStartOfDay,
  utcDayStartFromYmd,
  utcDayEndFromYmd,
  maxUtcDate,
} from "@/lib/trip-dates";

export type GroupSize = "SMALL" | "MEDIUM" | "LARGE";

export interface TripFilters {
  q?: string;
  from?: string;
  to?: string;
  category?: ActivityCategory;
  vibe?: Vibe;
  groupSize?: GroupSize;
}

export const tripRepo = {
  async findAll() {
    return prisma.trip.findMany({
      include: {
        organizer: {
          select: {
            id: true,
            name: true,
            image: true,
            organizerVerification: { select: { status: true } },
          },
        },
        images: { orderBy: { order: "asc" }, take: 1 },
        _count: {
          select: {
            participants: { where: { status: { not: "CANCELLED" } } },
          },
        },
      },
      orderBy: { date: "asc" },
    });
  },

  async findOpen(filters?: TripFilters) {
    const todayStart = utcStartOfDay(new Date());

    const andParts: Prisma.TripWhereInput[] = [
      { status: "OPEN" },
      // Sembunyikan trip dari organizer yang suspended — moderasi via panel admin.
      { organizer: { suspended: false } },
    ];

    if (filters?.category) {
      andParts.push({ category: filters.category });
    }

    if (filters?.vibe) {
      andParts.push({ vibe: filters.vibe });
    }

    if (filters?.groupSize === "SMALL") {
      andParts.push({ maxParticipants: { lte: 10 } });
    } else if (filters?.groupSize === "MEDIUM") {
      andParts.push({ maxParticipants: { gte: 11, lte: 20 } });
    } else if (filters?.groupSize === "LARGE") {
      andParts.push({ maxParticipants: { gte: 21 } });
    }

    if (!filters?.from && !filters?.to) {
      andParts.push({ date: { gte: todayStart } });
    } else {
      const userRangeStart = filters.from
        ? utcDayStartFromYmd(filters.from)
        : todayStart;
      const userRangeEnd = filters.to
        ? utcDayEndFromYmd(filters.to)
        : utcDayEndFromYmd("2099-12-31");

      const rangeStart = maxUtcDate(todayStart, userRangeStart);
      const rangeEnd = userRangeEnd;

      andParts.push({
        OR: [
          {
            AND: [
              { endDate: { not: null } },
              { date: { lte: rangeEnd } },
              { endDate: { gte: rangeStart } },
            ],
          },
          {
            AND: [
              { endDate: null },
              { date: { gte: rangeStart } },
              { date: { lte: rangeEnd } },
            ],
          },
        ],
      });
    }

    if (filters?.q) {
      andParts.push({
        OR: [
          { title: { contains: filters.q, mode: "insensitive" } },
          { destination: { contains: filters.q, mode: "insensitive" } },
          { location: { contains: filters.q, mode: "insensitive" } },
        ],
      });
    }

    const where: Prisma.TripWhereInput = { AND: andParts };

    return prisma.trip.findMany({
      where,
      include: {
        organizer: {
          select: {
            id: true,
            name: true,
            image: true,
            organizerVerification: { select: { status: true } },
          },
        },
        images: { orderBy: { order: "asc" }, take: 1 },
        participants: {
          where: { status: "CONFIRMED" },
          take: 10,
          orderBy: { createdAt: "asc" },
          select: {
            id: true,
            user: {
              select: {
                id: true,
                name: true,
                image: true,
                profile: { select: { interests: true } },
              },
            },
          },
        },
        _count: {
          select: {
            participants: { where: { status: { not: "CANCELLED" } } },
          },
        },
      },
      orderBy: { date: "asc" },
    });
  },

  async findById(id: string) {
    return prisma.trip.findUnique({
      where: { id },
      include: {
        organizer: {
          select: {
            id: true,
            name: true,
            email: true,
            image: true,
            organizerVerification: { select: { status: true } },
          },
        },
        images: { orderBy: { order: "asc" } },
        itineraryItems: {
          orderBy: [{ day: "asc" }, { order: "asc" }],
        },
        participants: {
          include: {
            user: {
              select: {
                id: true,
                name: true,
                image: true,
                profile: { select: { city: true, interests: true } },
              },
            },
          },
        },
        reviews: {
          orderBy: { createdAt: "desc" },
          include: {
            user: { select: { id: true, name: true, image: true } },
          },
        },
      },
    });
  },

  async countByOrganizerSince(organizerId: string, since: Date) {
    return prisma.trip.count({
      where: { organizerId, createdAt: { gte: since } },
    });
  },

  /**
   * Admin search lintas trip. Tidak filter berdasarkan status departure (admin
   * boleh lihat semua: OPEN/FULL/CLOSED/COMPLETED). Include _count peserta
   * aktif untuk indikator cepat.
   */
  async searchForAdmin(filters: {
    q?: string;
    status?: "OPEN" | "FULL" | "CLOSED" | "COMPLETED";
  }) {
    const where: Prisma.TripWhereInput = {};
    if (filters.status) {
      where.status = filters.status;
    }
    if (filters.q) {
      where.OR = [
        { title: { contains: filters.q, mode: "insensitive" } },
        { destination: { contains: filters.q, mode: "insensitive" } },
        { location: { contains: filters.q, mode: "insensitive" } },
        { organizer: { name: { contains: filters.q, mode: "insensitive" } } },
        { organizer: { email: { contains: filters.q, mode: "insensitive" } } },
      ];
    }
    return prisma.trip.findMany({
      where,
      include: {
        organizer: { select: { id: true, name: true, email: true } },
        images: { orderBy: { order: "asc" }, take: 1 },
        _count: {
          select: {
            participants: { where: { status: { not: "CANCELLED" } } },
            bookings: { where: { status: "PAID" } },
          },
        },
      },
      orderBy: { date: "desc" },
      take: 100,
    });
  },

  /** Semua trip yang dibuat user (semua status), terbaru dulu — untuk profil. */
  async findByOrganizerId(organizerId: string) {
    return prisma.trip.findMany({
      where: { organizerId },
      include: {
        images: { orderBy: { order: "asc" }, take: 1 },
        _count: {
          select: {
            participants: { where: { status: { not: "CANCELLED" } } },
          },
        },
      },
      orderBy: { date: "desc" },
    });
  },

  async create(data: Prisma.TripCreateInput) {
    return prisma.trip.create({ data });
  },

  async updateStatus(id: string, status: "OPEN" | "FULL" | "CLOSED" | "COMPLETED") {
    return prisma.trip.update({ where: { id }, data: { status } });
  },

  /**
   * Bulk transisi trip yang sudah lewat `cutoff` (start of today UTC) dari
   * status OPEN/FULL ke COMPLETED. Idempotent — second run tidak akan match
   * apa-apa karena status sudah berubah.
   *
   * Returns daftar id yang ter-update untuk telemetri/log.
   */
  async bulkCompletePastTrips(cutoff: Date) {
    const trips = await prisma.trip.findMany({
      where: {
        status: { in: ["OPEN", "FULL"] },
        OR: [
          { endDate: { lt: cutoff } },
          { AND: [{ endDate: null }, { date: { lt: cutoff } }] },
        ],
      },
      select: { id: true },
    });

    if (trips.length === 0) {
      return { count: 0, ids: [] as string[] };
    }

    const ids = trips.map((t) => t.id);
    const result = await prisma.trip.updateMany({
      where: {
        id: { in: ids },
        status: { in: ["OPEN", "FULL"] },
      },
      data: { status: "COMPLETED" },
    });

    return { count: result.count, ids };
  },
};
