import { Transaction } from 'sequelize'
import { AllowNull, BelongsTo, Column, CreatedAt, DataType, Default, ForeignKey, Table, UpdatedAt } from 'sequelize-typescript'
import { MEvent } from '@server/types/models/index.js'
import { VideoChannelModel } from './video-channel.js'
import { SequelizeModel } from '../shared/index.js'

export enum EventState {
  ACTIVE = 'active',
  DISABLED = 'disabled'
}

@Table({
  tableName: 'event',
  indexes: [
    {
      fields: [ 'channelId' ]
    },
    {
      fields: [ 'state' ]
    },
    {
      fields: [ 'startTime' ]
    }
  ]
})
export class EventModel extends SequelizeModel<EventModel> {
  @AllowNull(false)
  @Column
  declare title: string

  @AllowNull(true)
  @Column(DataType.TEXT)
  declare description: string | null

  @AllowNull(false)
  @Column
  declare startTime: Date

  @AllowNull(false)
  @Column
  declare endTime: Date

  @AllowNull(true)
  @Column
  declare thumbnailFilename: string | null

  @AllowNull(true)
  @Column(DataType.BLOB)
  declare thumbnailData: Buffer | null

  @AllowNull(true)
  @Column
  declare thumbnailMimeType: string | null

  @AllowNull(true)
  @Column(DataType.BIGINT)
  declare thumbnailSize: number | null

  @AllowNull(true)
  @Column
  declare thumbnailEtag: string | null

  @AllowNull(true)
  @Column(DataType.TEXT)
  declare liveUrl: string | null

  @AllowNull(false)
  @Default(EventState.ACTIVE)
  @Column
  declare state: EventState

  @CreatedAt
  declare createdAt: Date

  @UpdatedAt
  declare updatedAt: Date

  @ForeignKey(() => VideoChannelModel)
  @Column
  declare channelId: number

  @BelongsTo(() => VideoChannelModel, {
    foreignKey: {
      allowNull: false
    },
    onDelete: 'cascade'
  })
  declare Channel: Awaited<VideoChannelModel>

  static listByChannelId (channelId: number, transaction?: Transaction) {
    const query = {
      where: {
        channelId
      },
      order: [ [ 'startTime', 'DESC' ] ] as any,
      transaction
    }

    return EventModel.findAll<MEvent>(query)
  }

  static findByIdAndChannelId (eventId: number, channelId: number, transaction?: Transaction) {
    const query = {
      where: {
        id: eventId,
        channelId
      },
      transaction
    }

    return EventModel.findOne<MEvent>(query)
  }

  static loadByThumbnailFilename (thumbnailFilename: string, transaction?: Transaction) {
    return EventModel.findOne<MEvent>({
      where: {
        thumbnailFilename
      },
      transaction
    })
  }

  static listPublicEvents (limit?: number, states?: string[]) {
    const query: any = {
      order: [ [ 'startTime', 'DESC' ] ] as any,
      limit
    }

    // Only filter by state if explicitly provided; otherwise return all events
    if (states && states.length > 0) {
      query.where = { state: states }
    }

    return EventModel.findAll<MEvent>(query)
  }

  static async deleteByIdAndChannelId (eventId: number, channelId: number, transaction?: Transaction) {
    const event = await EventModel.findByIdAndChannelId(eventId, channelId, transaction)
    if (!event) return false

    await event.destroy({ transaction })
    return true
  }

  static async updateEventState (eventId: number, newState: EventState, transaction?: Transaction) {
    const query = {
      where: {
        id: eventId
      },
      transaction
    }

    return EventModel.update({ state: newState }, query)
  }

  toFormattedJSON (this: EventModel) {
    return {
      id: this.id,
      title: this.title,
      description: this.description,
      startTime: this.startTime.toISOString(),
      endTime: this.endTime.toISOString(),
      thumbnailFilename: this.thumbnailFilename,
      liveUrl: this.liveUrl,
      state: this.state,
      channelId: this.channelId,
      createdAt: this.createdAt.toISOString(),
      updatedAt: this.updatedAt.toISOString()
    }
  }

  toLogKeys (this: EventModel) {
    return {
      id: this.id,
      title: this.title,
      state: this.state,
      startTime: this.startTime,
      endTime: this.endTime,
      channelId: this.channelId
    }
  }
}
