import { ConflictException, Injectable, NotFoundException } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model, Types } from 'mongoose'
import {
  AvailabilitySchedule,
  AvailabilityScheduleDocument,
  DateOverride,
  WeeklyRule,
} from '../../schemas/availability-schedule.schema.js'
import { EventType, EventTypeDocument } from '../../schemas/event-type.schema.js'

export interface AvailabilityInput {
  name: string
  timezone: string
  weeklyRules: WeeklyRule[]
  dateOverrides?: DateOverride[]
}

@Injectable()
export class AvailabilityService {
  constructor(
    @InjectModel(AvailabilitySchedule.name)
    private readonly model: Model<AvailabilityScheduleDocument>,
    @InjectModel(EventType.name)
    private readonly eventTypeModel: Model<EventTypeDocument>,
  ) {}

  list(tenantId: Types.ObjectId, hostId: Types.ObjectId): Promise<AvailabilityScheduleDocument[]> {
    return this.model.find({ tenantId, hostId }).sort({ name: 1 }).exec()
  }

  create(tenantId: Types.ObjectId, hostId: Types.ObjectId, input: AvailabilityInput): Promise<AvailabilityScheduleDocument> {
    return this.model.create({
      tenantId,
      hostId,
      name: input.name,
      timezone: input.timezone,
      weeklyRules: input.weeklyRules,
      dateOverrides: input.dateOverrides ?? [],
    })
  }

  async get(tenantId: Types.ObjectId, id: string): Promise<AvailabilityScheduleDocument> {
    const doc = await this.model.findOne({ _id: id, tenantId }).exec()
    if (!doc) throw new NotFoundException('Availability schedule not found')
    return doc
  }

  async update(tenantId: Types.ObjectId, id: string, input: Partial<AvailabilityInput>): Promise<AvailabilityScheduleDocument> {
    const doc = await this.get(tenantId, id)
    if (input.name !== undefined) doc.name = input.name
    if (input.timezone !== undefined) doc.timezone = input.timezone
    if (input.weeklyRules !== undefined) doc.weeklyRules = input.weeklyRules
    if (input.dateOverrides !== undefined) doc.dateOverrides = input.dateOverrides
    return doc.save()
  }

  async remove(tenantId: Types.ObjectId, id: string): Promise<void> {
    // Don't orphan event types: a deleted schedule would break their slot
    // computation. Require the caller to reassign/delete those first.
    const inUse = await this.eventTypeModel.countDocuments({ tenantId, availabilityScheduleId: id }).exec()
    if (inUse > 0) {
      throw new ConflictException(`This schedule is used by ${inUse} event type(s). Reassign or delete them first.`)
    }
    const res = await this.model.deleteOne({ _id: id, tenantId }).exec()
    if (res.deletedCount === 0) throw new NotFoundException('Availability schedule not found')
  }
}
