import { IdParam, PagingQuery } from '../common/types'
import {
	CategoryAttribute,
	EventAttribute,
	InformationEmailAttribute,
	QuestionnaireAttribute,
	SectorAttribute,
	TicketConfigAttribute,
	TicketDiscountAttribute,
	TimeslotAttribute,
} from '../common/attributes'
import { Organizer } from '../account'
import { Venue } from '../venue'
import { Query } from '../common/query'

/**
 * Event interface
 */
export interface Event {
	id: number
	name: string
	status: EventStatus
	type: string
	startAt: Date
	endAt: Date
	createdAt: Date
	mainImageUri: string
	sectorsMapImageUri: string
	description: string
	tos: string
	contactEmail: string
	contactPhone: string
	gateTime: Date
	venueId: string
	organizerId: string
	enrollmentId: string
	chartKey: string
	rulesetKey: string
	kycLevelId: number
	ticketActivationPeriod?: number
	localTicketValidation?: boolean
	localValidationServerUrl?: string
	ticketConfig: TicketConfig[]
	subcategory: Subcategory
	sector: Sector[]
	ticketDiscount: TicketDiscount[]
	occurrence: Occurrence[]
	timeslot: Timeslot[]
	ticketFormat: TicketFormat[]
	visible: boolean
	timezoneName?: string
	pdfTemplateId?: number
	venue?: Venue
}

export interface UpdatableEvent {
	name?: string
	startAt?: Date
	endAt?: Date
	mainImageUri?: string
	sectorsMapImageUri?: string
	description?: string
	tos?: string
	contactEmail?: string
	contactPhone?: string
	gateTime?: Date
	venueId?: string
	chartKey?: string
	rulesetKey?: string
	kycLevelId?: number
	ticketActivationPeriod?: number
	localTicketValidation?: boolean
	localValidationServerUrl?: string
	visible?: boolean
	timezoneName?: string
	pdfTemplateId?: number
}

export interface NewEvent {
	startAt: Date
	endAt: Date
	gateTime: Date
	name: string
	venueId: string
	mainImageUri?: string
	sectorsMapImageUri?: string
	description?: string
	tos?: string
	contactEmail?: string
	contactPhone?: string
	kycLevelId?: number
	ticketActivationPeriod?: number
	localTicketValidation?: boolean
	localValidationServerUrl?: string
	ticketConfig: TicketConfig[]
	ticketDiscount?: TicketDiscount[]
	sector?: Sector[]
	subcategory: Subcategory
	occurrence?: Occurrence[]
	timeslot?: Timeslot[]
	ticketFormat?: TicketFormat[]
	visible?: boolean
	timezoneName?: string
	pdfTemplateId?: number
}

/**
 * Occurrence interface
 */
export interface Occurrence {
	id: number
	status: EventStatus
	type: string
	createdAt: Date
	startAt: Date
	endAt: Date
	gateTime: Date
	venueId: string
	organizerId: string
	enrollmentId: string
	chartKey: string
	rulesetKey: string
	ticketActivationPeriod?: number
	ticketConfig: TicketConfig[]
	sector: Sector[]
	subcategory: Subcategory
	timeslot: Timeslot[]
	visible?: boolean
}

/**
 * Sector interface
 */
export interface Sector {
	id: number
	name: string
	capacity: number
	ticketConfig: TicketConfig[]
	reservedTickets: number
	availableTickets: number
}

/**
 * Subcategory interface
 */
export interface Subcategory {
	id: number
	name: string
}

/**
 * Category interface
 */
export interface Category {
	id: number
	name: string
	subcategory: Subcategory[]
}

export interface ListCategoryQuery extends PagingQuery {
	with?: CategoryAttribute
	sort_by?: string
	direction?: string
}

/**
 * Ticket discount interface
 */
export interface TicketDiscount {
	id: number
	name: string
	type: string
	value: number
	quantity: number
	reservedTickets: number
	availableTickets: number
	startAt: Date
	endAt: Date
	ticketConfig?: TicketConfig[],
	code?: string,
	minQuantity?: number,
	maxQuantity?: number
}

/**
 * Ticket configuration interface
 */
export interface TicketConfig {
	id: number
	availableTickets: number
	createdAt: Date
	startSaleAt: Date
	endSaleAt: Date
	ticketsValidFrom: Date
	ticketsValidTo: Date
	faceValue: number
	taxRate?: number
	taxIncluded?: boolean
	pricingType: PricingType
	name: string
	description?: string
	quantity: number
	currency: string
	absorbFees: boolean
	ticketsPerUser: number
	secondaryMarketRulesetId?: string
	imageUri?: string
	videoUri?: string
	thumbnailUri?: string
	questionnaireId?: number
	status?: TicketConfigStatus
	ticketDiscount?: TicketDiscount[]
	sector?: Sector[]
	timeslot?: Timeslot[]
	promoSection?: PromoSection[]
	dependsOn?: TicketConfig[]
	visible?: boolean
	pdfTemplateId?: number
}

/**
 * Timeslot interface
 */
export interface Timeslot {
	id: number
	name: string
	capacity: number
	startAt: Date
	endAt: Date
	ticketConfig: TicketConfig[]
	reservedTickets: number
	availableTickets: number
}

/**
 * Ticket format interface
 */
export interface TicketFormat {
	id: number
	name?: string
	displayName?: string
}

export interface Questionnaire {
	id: number
	name: string
	organizerID: string
	questionnaireItem: QuestionnaireItem[]
}

export interface QuestionnaireItem {
	id: number
	questionID: number
	questionnaireID: number
	required: boolean
	ordinalNumber: number
	question: Question
}

export interface Question {
	id: number
	key: string
	type: string
	content: string
	organizerID: string
}

export interface TicketHolder {
	id: number
	response: Record<string, any>
	questionnaire?: Questionnaire
}

export interface Ticket {
	id: number
	seqNum: number
	status: TicketStatus
	kycStatus: string
	enrollmentId: string
	seatId: string
	format: string
	ticketConfig: TicketConfig
	sector: Sector
	ticketHolder: TicketHolder
	ticketDiscount: TicketDiscount[]
	timeslot: Timeslot
	updatedAt: Date
}

export interface OrganizerSpecificId {
	id: number
	organizerId: string
}
export interface InformationEmailId {
	id: number
	eventId: number
	organizerId: string
}

export interface OrganizerName {
	name: string
}

export interface TicketConfigId {
	eventId: number
	organizerId: string
	ticketConfigId: number
}

export interface TicketDiscountIdParam {
	id: number
	organizerId: string
	eventId: number
}

export interface PrivateEventParam {
	id: number
	access_token: string
}

export interface CommonEventQuery {
	query?: string
	include_occurrences?: boolean
	with?: EventAttribute
	organizer_id?: string
}

export interface ListEventsQuery extends CommonEventQuery {
	start_at?: [Date, Date]
	sort_by?: string
	direction?: string
	future_events?: boolean
	name?: string
}

export interface ListOrganizerEventsQuery extends PagingQuery {
	statuses?: EventStatus[]
	with?: EventAttribute
	include_ticket_availability?: boolean
	include_occurrences?: boolean
	name?: string,
	sort_by?: string,
	venue_id?: number,
	category_id?: number,
	subcategory_id?: number,
	organizer_id?: string,
	enrollment_id?: string,
	created_at?: string
}

export interface SingleOrganizerEventQuery {
	with?: EventAttribute
	include_ticket_availability?: boolean
	include_occurrences?: boolean
}

export interface ListOrganizerEventTicketConfigsQuery {
	with?: TicketConfigAttribute,
	sort_by?: string,
	name?: string,
	id?: number,
	created_at?: string
}

export interface SingleEventQuery extends IdParam, CommonEventQuery {}

export interface PrivateEventQuery
	extends PrivateEventParam,
		CommonEventQuery {}

export interface MyEventsQuery {
	date?: MyEventsEventDateFilter | string
}

export enum MyEventsEventDateFilter {
	Future = 'future',
	Past = 'past',
	All = 'all',
}

export interface PublicKey {
	publicKey: string
}

export interface TicketCount {
	id: number
	name: string
	issuedTickets: number
	activatedTickets: number
	invalidatedTickets: number
}

export interface TicketQrCode {
	content: string
	ticketId: number
}

export interface QrCodeTicket extends Ticket {
	ticketQrCode: TicketQrCode
	updatedAt: Date
}

export interface QrCodeTicketConfig extends TicketConfig {
	status: TicketConfigStatus
	taxRate: number
	taxIncluded: boolean
	visible: boolean
	description: string
	secondaryMarketRulesetId: string
	imageUri: string
	videoUri: string
	kycLevelId: number
	questionnaireId: number
	ticket: QrCodeTicket[]
}

export interface MyEventsPromoSection {
	id: number
	name: string
	content: string
	visible: boolean
	ordinalNumber: number
}

export interface MyEventsTicketConfig
	extends Omit<QrCodeTicketConfig, 'promoSection'> {
	userHolds: number
	promoSection: MyEventsPromoSection[]
}

export interface MyEventsEvent extends Omit<Event, 'ticketConfig'> {
	organizer: Organizer
	venue: Venue
	ticketConfig: MyEventsTicketConfig[]
}

export interface NftDrop {
	id?: number
	senderId?: string
	organizerId: string
	createdAt?: string
	chaincodeId: string
	dropId?: number
	note?: string
	nftId: number
	sentAt?: string

	nftDropFilter?: NftDropFilter[]
}

export type CreateNftDrop = {
	organizerId: string
	chaincodeId: string
	note?: string
	nftId: number
	nftDropFilter: CreateNftDropFilter[]
}

export type UpdateNftDrop = {
	organizerId: string
	id: number
	chaincodeId?: string
	note?: string
	nftId?: number
	nftDropFilter?: CreateNftDropFilter[]
}

export interface NftDropFilterRelations extends Query {
	event?: boolean
	ticket_config?: boolean
}

export interface NftDropRelations extends Query {
	nft_drop_filter: NftDropFilterRelations
}

export interface NftDropQuery extends PagingQuery {
	with?: NftDropRelations
	sort_by?: string
}

export class NftDropFilter {
	id?: number
	ticketStatuses?: string[]
	eventId?: number
	ticketConfigId?: number
	userId?: string

	nftDrop?: NftDrop
	event?: Event
	ticketConfig?: TicketConfig
}

export interface NftDropFilterId {
	id: number
	organizerId: string
	nftDropId: number
}

export interface SingleNftDropQuery {
	with?: NftDropRelations
}

export type CreateNftDropFilter = {
	ticketStatuses?: string[]
	eventId?: number
	ticketConfigId?: number
	userId?: string
}

export enum EventStatus {
	Draft = 'draft',
	Committed = 'committed',
	Published = 'published',
	Updated = 'updated',
	Canceled = 'canceled',
}

export enum TicketStatus {
	// Created tickets
	Draft = 'draft',
	// Tickets after publishing to blockchain
	Available = 'available',
	// When associated with an order/ about to be issued
	Reserved = 'reserved',
	// When a payment is done or issue is called
	Confirmed = 'confirmed',
	// After they are assigned to the owner on the blockchain
	Issued = 'issued',
	// Activated through the wallet
	Activated = 'activated',
	// Used
	Invalidated = 'invalidated',
	// Event was canceled
	Unavailable = 'unavailable',
}

export enum TicketConfigStatus {
	Draft = 'draft',
	Updated = 'updated',
	Committed = 'committed',
	Published = 'published',
}

export enum DiscountType {
	Amount = 'amount',
	Percent = 'percent',
}

export enum PricingType {
	Paid = 'paid',
	Free = 'free',
	Donation = 'donation',
}

export enum DispatchedInfoStatus {
	Draft = 1,
	Sent = 2,
	Delivered = 3,
}

export interface SingleTicketDiscountQuery {
	with?: TicketDiscountAttribute
}

export interface ListTicketDiscountQuery extends PagingQuery {
	with?: TicketDiscountAttribute,
	id?: number,
	type?: DiscountType,
	name?: string,
	code?: string,
	sort_by?: string
}

/**
 * Create ticket discount type
 */
export type CreateTicketDiscount = {
	name: string
	type: DiscountType
	value: number
	quantity: number
	startAt: Date
	endAt: Date
	code?: string
	minQuantity?: number
	maxQuantity?: number
	ticketConfig?: TicketConfig[]
}

/**
 * Update ticket discount type
 */
export type UpdateTicketDiscount = {
	id: number
	name?: string
	type?: DiscountType
	value?: number
	quantity?: number
	startAt?: Date
	endAt?: Date
	code?: string
	minQuantity?: number
	maxQuantity?: number
	ticketConfig?: TicketConfig[]
}

/**
 * Create discount batch type
 */
export type CreateDiscountBatch = {
	quantity: number
}

export type PromoSection = {
	id: number
	name: string
	content: string
	visible: boolean
	ordinalNumber: number
	createdBy: string
	createdAt: string
	updatedBy?: string
	updatedAt?: string
}

export type CreatePromoSection = {
	name: string
	content: string
	visible: boolean
	ordinalNumber: number
}

export type UpdatePromoSection = {
	name?: string
	content?: string
	visible?: boolean
	ordinalNumber?: number
}

export type PromoSectionId = {
	eventId: number
	organizerId: string
	ticketConfigId: number
	id: number
}

/**
 * Create ticket configuration interface
 */
export interface CreateTicketConfig {
	startSaleAt?: Date
	endSaleAt?: Date
	ticketsValidFrom?: Date
	ticketsValidTo?: Date
	faceValue: number
	taxRate?: number
	taxIncluded?: boolean
	pricingType: PricingType
	name: string
	description?: string
	quantity: number
	currency: string
	absorbFees: boolean
	ticketsPerUser?: number
	secondaryMarketRulesetId?: string
	imageUri?: string
	videoUri?: string
	thumbnailUri?: string
	kycLevelId?: number
	questionnaireId?: number
	status?: TicketConfigStatus
	ticketDiscount?: TicketDiscount[]
	sector?: Sector[]
	timeslot?: Timeslot[]
	promoSection?: PromoSection[]
	dependsOn?: TicketConfig[]
	visible?: boolean
	pdfTemplateId?: number
}

export type AppliedTicketConfig = Pick<TicketConfig, 'id'>

export type CreateSector = {
	name: string
	capacity: number
	ticketConfig: AppliedTicketConfig[]
}

export type UpdateSector = {
	name?: string
	capacity?: number
	ticketConfig?: AppliedTicketConfig[]
}

export type SectorId = {
	eventId: number
	organizerId: string
	id: number
}

export type SingleSectorQuery = {
	with?: SectorAttribute
}

export type ListSectorQuery = {
	with?: SectorAttribute
}

export type CreateTimeslot = {
	name: string
	capacity: number
	startAt: Date
	endAt: Date
	ticketConfig?: AppliedTicketConfig[]
}

export type UpdateTimeslot = {
	name?: string
	capacity?: number
	startAt?: Date
	endAt?: Date
	ticketConfig?: AppliedTicketConfig[]
}

export type TimeslotId = {
	eventId: number
	organizerId: string
	id: number
}

export type SingleTimeslotQuery = {
	with?: TimeslotAttribute
}

export type ListTimeslotsQuery = {
	with?: TimeslotAttribute
}

export interface ListInformationEmailQuery extends PagingQuery {
	with?: InformationEmailAttribute
	sort_by?: string
}

export type SingleInformationEmailQuery = {
	with?: InformationEmailAttribute
}

export type CreateInformationEmail = {
	subject: string
	body: string
	template?: string
	informationEmailFilter?: InformationEmailFilter[]
}

export type UpdateInformationEmail = {
	subject?: string
	body?: string
	template?: string
}

export interface InformationEmail {
	id: number
	subject: string
	body: string
	createdBy: string
	dispatchedInfo: DispatchedInfoStatus
	sentAt: string
	createdAt: string
	template: string
	informationEmailFilter: InformationEmailFilter[]
}

export interface InformationEmailFilter {
	id: number
	ticketConfigId: number
	ticketConfig: TicketConfig
}

export interface EventHolderList {
	id: number
	name: string
	organizerId: string
	ticketConfig: TicketConfigHolderList[]
}

export interface TicketConfigHolderList {
	id: number
	name: string
	holders: string[] // Array of ticket holder enrollment IDs
}

export interface ListQuestionnaireQuery extends PagingQuery {
	with?: QuestionnaireAttribute
	sort_by?: string
}

export type QuestionnaireQuery = {
	with?: QuestionnaireAttribute
}

export interface CreateQuestionnaireItem {
	questionId: number
	questionnaireId?: number
	required?: boolean
}

export interface CreateQuestionnaire {
	name: string
	questionnaireItem: CreateQuestionnaireItem[]
}

export interface UpdateQuestionnaireItem extends CreateQuestionnaireItem {
	id?: number
	ordinalNumber?: number
}

export interface UpdateQuestionnaire {
	name?: string
	questionnaireItem: UpdateQuestionnaireItem[]
}

export interface ListQuestionQuery extends PagingQuery {
	sort_by?: string
}

export interface CreateQuestion {
	key: string,
	type: string,
	content: string,
	questionnaireItem?: QuestionnaireItem
}

export interface SendTicketItem {
	quantity: number,
	timeslotId?: number,
	sectorId?: number,
	ticketConfigId: number,
	ticketDiscount?: number[],
	selectedSeats?: string[]
}

export interface SendTicketsData {
	eventId: number,
	format: string,
	sendTicketItems: SendTicketItem[],
	note?: string,
	ownerEmails: string[]
}

export interface SentTicket {
	id: number,
	seqNum: number,
	ticketConfigId: number,
	timeslotId?: number,
	sectorId?: number,
	seatId?: string,
	sendTicketRequestId: number
}
export interface SendTicketsResponse {
	tickets: SentTicket[]
}
