import { AxiosInstance } from 'axios'
import queryString from 'query-string'

import { HealthStatus, IdParam } from '../common/types'
import { Venue, VenueQuery, VenueQueryWithId } from './types'

/**
 * Service class for venue service API calls.
 */
export class VenueService {
	constructor(readonly client: AxiosInstance, readonly version: string) {}

	/**
	 * Returns true if the service is reachable
	 *
	 * @returns Services' online status
	 */
	async health(): Promise<HealthStatus> {
		try {
			const res = await this.client.get(`venue/health`)
			if (res.data.status === 'ok') {
				return { online: true }
			}
		} catch (e) {
			// Do nothing
		}

		return { online: false }
	}

	/**
	 * Gets venues matching specified criteria.
	 *
	 * @param req filtering options
	 * @returns an array of venues matching the criteria
	 */
	async getVenues(req: VenueQuery = {}): Promise<Venue[]> {
		const query = queryString.stringify(
			{
				...req,
				q: req.query,
				sort_by: req.sortBy,
				with: 'address.position',
			},
			{ arrayFormat: 'comma' }
		)

		const res = await this.client.get(`venue/${this.version}/venue?${query}`)

		return res.data.data
	}

	/**
	 * Gets a venue by its id.
	 *
	 * @param req venue ID and query options
	 * @returns the requested venue
	 */
	async getVenue(options: VenueQueryWithId): Promise<Venue> {
		const query = queryString.stringify(
			{
				...options,
				q: options.query,
				sort_by: options.sortBy,
				with: 'address.position',
			},
			{ arrayFormat: 'comma' }
		)

		const res = await this.client.get(
			`venue/${this.version}/venue/${options.id}?${query}`
		)

		return res.data.data
	}

	/**
	 * Creates a new venue
	 *
	 * @param newVenue venue data
	 * @returns the created venue
	 */
	async createVenue(newVenue: Venue): Promise<Venue> {
		const res = await this.client.post(`venue/${this.version}/venue`, newVenue)

		return res.data.data
	}

	/**
	 * Updates a venue
	 *
	 * @param newData venue data, must contain the venue id
	 * @returns the updated venue
	 */
	async updateVenue(newData: Partial<Venue>): Promise<Venue> {
		const res = await this.client.patch(
			`venue/${this.version}/venue/${newData.id}`,
			newData
		)

		return res.data.data
	}

	/**
	 * Updates a venue
	 *
	 * @param newData venue data, must contain the venue id
	 * @returns the updated venue
	 */
	async deleteVenue(newData: IdParam): Promise<void> {
		await this.client.delete(`venue/${this.version}/venue/${newData.id}`)
	}
}
