import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose'
import { HydratedDocument, Types } from 'mongoose'

export type EventTypeDocument = HydratedDocument<EventType>

export type LocationType = 'jitsi' | 'phone' | 'in_person' | 'custom'

// How a booking on this event type picks the host whose calendar the appointment
// lands on. 'single' (default) keeps the classic one-host-per-event-type behavior
// unchanged. 'round_robin' distributes across a pool of hosts: slots are the union
// of every pooled host's free time, and at booking time a free pooled host is
// chosen (least-recently-booked) and the event is written to THAT host's calendar.
export type EventTypeAssignment = 'single' | 'round_robin'

// A bookable appointment type for a host (e.g. "30-min consultation"). Carries
// the booking rules slot computation needs: duration, granularity, buffers,
// notice window, and horizon.
@Schema({ collection: 'scheduling_event_types', timestamps: true })
export class EventType {
  @Prop({ type: Types.ObjectId, ref: 'Tenant', required: true, index: true })
  tenantId!: Types.ObjectId

  @Prop({ type: Types.ObjectId, ref: 'Host', required: true, index: true })
  hostId!: Types.ObjectId

  @Prop({ required: true, lowercase: true, trim: true })
  slug!: string

  @Prop({ required: true, trim: true })
  title!: string

  @Prop({ trim: true })
  description?: string

  @Prop({ required: true, min: 1 })
  durationMinutes!: number

  // Granularity of offered start times (e.g. 15 => :00/:15/:30/:45).
  @Prop({ required: true, min: 1, default: 15 })
  slotIntervalMinutes!: number

  @Prop({ min: 0, default: 0 })
  bufferBeforeMinutes!: number

  @Prop({ min: 0, default: 0 })
  bufferAfterMinutes!: number

  // Earliest bookable time relative to now.
  @Prop({ min: 0, default: 0 })
  minimumNoticeMinutes!: number

  // Booking horizon — how far ahead slots are offered.
  @Prop({ min: 1, default: 60 })
  maximumDaysInFuture!: number

  @Prop({ type: Types.ObjectId, ref: 'AvailabilitySchedule', required: true })
  availabilityScheduleId!: Types.ObjectId

  @Prop({ enum: ['jitsi', 'phone', 'in_person', 'custom'], default: 'jitsi' })
  locationType!: LocationType

  // Free text for phone / in_person / custom (e.g. a phone number or address).
  @Prop({ trim: true })
  locationDetails?: string

  @Prop({ trim: true })
  color?: string

  // When true (default), all-day calendar events on the host's calendar are NOT
  // treated as busy — so e.g. an all-day "On leave" marker or a holiday does not
  // block every slot of the day. Set false to honour all-day events as busy.
  @Prop({ default: true })
  ignoreAllDayEvents!: boolean

  @Prop({ default: true, index: true })
  isActive!: boolean

  // Host-assignment strategy. Defaults to 'single' so existing event types keep
  // their original single-host behavior with no migration needed.
  @Prop({ enum: ['single', 'round_robin'], default: 'single' })
  assignment!: EventTypeAssignment

  // Round-robin host pool. Ignored unless assignment === 'round_robin'. The owning
  // host (hostId) is always treated as part of the effective pool so a misconfigured
  // empty pool degrades gracefully to single-host behavior on the owner.
  @Prop({ type: [Types.ObjectId], ref: 'Host', default: [] })
  hostPool!: Types.ObjectId[]
}

export const EventTypeSchema = SchemaFactory.createForClass(EventType)
EventTypeSchema.index({ tenantId: 1, hostId: 1, slug: 1 }, { unique: true })
