import { AxiosInstance } from 'axios'

import {
	GeneralNotification,
	ListNotificationQuery,
	Notification,
	NotificationContent,
	NotificationResponse,
} from './types'
import { OrganizerSpecificId, TicketConfigId } from '../event'
import { getStringifiedQuery } from '../common/query'
import { IdParam, StatusResponse } from '../common/types'

/**
 * Service class for sending notifications.
 */
export class NotificationService {
	constructor(
		readonly client: AxiosInstance,
		readonly tenantClient: AxiosInstance,
		readonly version: string
	) {}

	/**
	 * Sends a notification via the account service
	 * @param data the content of the notification and its topic
	 * @returns was the notification sent successfully
	 */
	async sendNotification(data: Notification): Promise<StatusResponse> {
		const res = await this.client.post(
			`account/${this.version}/notification/send`,
			data
		)

		return res.data.data
	}

	/**
	 * Sends a notification via the account service
	 * @param id.id the id of the notification to be sent
	 * @returns was the notification sent successfully
	 */
	async sendExistingNotification(id: IdParam): Promise<StatusResponse> {
		const res = await this.client.post(
			`account/${this.version}/notification/${id.id}/send`,
			{}
		)

		return res.data.data
	}

	/**
	 * Sends a notification to all the users who are holding tickets for this event
	 * @param data the content of the notification
	 * @returns was the notification sent successfully
	 */
	async sendNotificationForEvent(
		id: OrganizerSpecificId,
		data: NotificationContent
	): Promise<StatusResponse> {
		const res = await this.tenantClient.post(
			`event/${this.version}/organizer/${id.organizerId}/event/${id.id}/notification`,
			data
		)

		return res.data.data
	}

	/**
	 * Sends a notification to all the users who are holding tickets for this ticket config
	 * @param data the content of the notification
	 * @returns was the notification sent successfully
	 */
	async sendNotificationForTicketConfig(
		id: TicketConfigId,
		data: NotificationContent
	): Promise<StatusResponse> {
		const res = await this.tenantClient.post(
			`event/${this.version}/organizer/${id.organizerId}/event/${id.eventId}/ticket_config/${id.ticketConfigId}/notification`,
			data
		)

		return res.data.data
	}

	/**
	 * Retrieves a list of notifications based on the provided query parameters.
	 * @param query - The query parameters for filtering the notifications (optional).
	 */
	async listNotifications(
		query: ListNotificationQuery = {}
	): Promise<NotificationResponse[]> {
		const res = await this.client.get(
			`account/${this.version}/notification?${getStringifiedQuery(query)}`
		)

		return res.data.data
	}

	/**
	 * Fetches a previously created notification
	 * @param id.id the id of the notification to be fetched
	 * @returns requested notification
	 */
	async getNotification(id: IdParam): Promise<NotificationResponse> {
		const res = await this.client.get(
			`account/${this.version}/notification/${id.id}`
		)

		return res.data.data
	}

	/**
	 * Creates a new notification.
	 * @param data The notification data.
	 */
	async createNotification(
		data: GeneralNotification
	): Promise<NotificationResponse> {
		const res = await this.client.post(
			`account/${this.version}/notification`,
			data
		)

		return res.data.data
	}

	/**
	 * Updates a notification with the specified ID.
	 *
	 * @param {IdParam} id - The ID of the notification to update.
	 * @param {GeneralNotification} data - The updated notification data.
	 */
	async updateNotification(
		id: IdParam,
		data: Partial<GeneralNotification>
	): Promise<NotificationResponse> {
		const res = await this.client.patch(
			`account/${this.version}/notification/${id.id}`,
			data
		)

		return res.data.data
	}

	/**
	 * Deletes a notification by its ID.
	 * @param id - The ID of the notification to delete.
	 */
	async deleteNotification(id: IdParam) {
		const res = await this.client.delete(
			`account/${this.version}/notification/${id.id}`
		)

		return res.data.data
	}
}
