import { getPayload, PaginatedDocs } from 'payload'
import config from '@/payload.config'
import { EventOccurrence } from '@/payload-types'

type ListArgs = {
  parishId?: string
  groupId?: string
  eventId?: string
  limit?: number
  page?: number
  fromDate?: Date
  toDate?: Date
}

/**
 * Fetch upcoming event occurrences, joined to their parent event. Always
 * filters to occurrences whose parent event is published.
 */
export async function fetchUpcomingOccurrences(
  args?: ListArgs,
): Promise<PaginatedDocs<EventOccurrence>> {
  const {
    parishId,
    groupId,
    eventId,
    limit = 30,
    page = 0,
    fromDate = new Date(),
    toDate,
  } = args || {}

  const query: any = {
    and: [
      { date: { greater_than_equal: fromDate.toISOString() } },
      { 'event._status': { equals: 'published' } },
    ],
  }

  if (toDate) {
    query.and.push({ date: { less_than: toDate.toISOString() } })
  }
  if (eventId) {
    query.and.push({ event: { equals: eventId } })
  }
  if (parishId) {
    query.and.push({ 'event.parish': { equals: parishId } })
  }
  if (groupId) {
    query.and.push({ 'event.group': { equals: groupId } })
  }

  const payload = await getPayload({ config })
  return payload.find({
    collection: 'eventOccurrence',
    sort: 'date',
    where: query,
    depth: 2,
    limit,
    page,
  }) as Promise<PaginatedDocs<EventOccurrence>>
}

/**
 * Fetch past event occurrences (most recent first), joined to their parent
 * event. Always filters to occurrences whose parent event is published.
 */
export async function fetchPastOccurrences(
  args?: ListArgs,
): Promise<PaginatedDocs<EventOccurrence>> {
  const {
    parishId,
    groupId,
    eventId,
    limit = 30,
    page = 0,
    fromDate,
    toDate = new Date(),
  } = args || {}

  const query: any = {
    and: [
      { date: { less_than: toDate.toISOString() } },
      { 'event._status': { equals: 'published' } },
    ],
  }

  if (fromDate) {
    query.and.push({ date: { greater_than_equal: fromDate.toISOString() } })
  }
  if (eventId) {
    query.and.push({ event: { equals: eventId } })
  }
  if (parishId) {
    query.and.push({ 'event.parish': { equals: parishId } })
  }
  if (groupId) {
    query.and.push({ 'event.group': { equals: groupId } })
  }

  const payload = await getPayload({ config })
  return payload.find({
    collection: 'eventOccurrence',
    sort: '-date',
    where: query,
    depth: 2,
    limit,
    page,
  }) as Promise<PaginatedDocs<EventOccurrence>>
}

/**
 * Fetch upcoming occurrences, falling back to past occurrences if there
 * are no upcoming ones.
 */
export async function fetchUpcomingOrPastOccurrences(
  args?: ListArgs,
): Promise<PaginatedDocs<EventOccurrence>> {
  const upcoming = await fetchUpcomingOccurrences(args)
  if (upcoming.docs.length > 0) return upcoming
  return fetchPastOccurrences(args)
}

/**
 * Fetch a single occurrence by id with its parent event populated.
 * Returns undefined if not found or if the id is malformed.
 */
export async function fetchOccurrenceById(
  id: string,
  draft: boolean = false,
): Promise<EventOccurrence | undefined> {
  try {
    const payload = await getPayload({ config })
    return await payload.findByID({
      collection: 'eventOccurrence',
      id,
      depth: 2,
      draft,
    })
  } catch {
    return undefined
  }
}
