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

import { buildQuery } from '../common/query'
import { HealthStatus, ListInfo } from '../common/types'
import {
	Categories,
	ExternalEvent,
	ExternalEventsInfo,
	ExternalEventsQuery,
	ListEventsQuery,
	ProviderSpecificId,
} from './types'
import { Event, ListCategoryQuery } from 'src/event'

export class BAMgregatorService {
	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(`/health`)
			if (res.data.status === 'ok') {
				return { online: true }
			}
		} catch (e) {
			// Do nothing
		}

		return { online: false }
	}

	/**
	 * Returns a list of active events.
	 *
	 * @param req.q String value for text-based search on event
	 * @param req.start_at Date range where the event start_at field is filtered
	 * @param req.include_occurrences If true, in case of recurring events it includes occurrences
	 * @param req.with Field selector query attribute
	 * @returns
	 */
	async listEvents(req: ListEventsQuery = {}): Promise<ListInfo<Event>> {
		let queryWith = undefined
		if (req.with) {
			queryWith = buildQuery(req.with)
		}
		let queryStartAt = undefined
		if (
			req.start_at?.length === 2 &&
			req.start_at[0] instanceof Date &&
			req.start_at[1] instanceof Date
		) {
			queryStartAt = `${req.start_at[0].toISOString()};${req.start_at[1].toISOString()}`
		}
		const query = queryString.stringify(
			{
				include_occurrences: req.include_occurrences,
				q: req.query,
				public: true,
				with: queryWith,
				start_at: queryStartAt,
				organizer_id: req.organizer_id,
				sort_by: req.sort_by,
				direction: req.direction,
				future_events: req.future_events,
				name: req.name,
			},
			{ arrayFormat: 'comma', skipNull: true, skipEmptyString: true }
		)

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

		return res.data
	}

	/**
	 * Returns a list of external events.
	 *
	 * @param req.sort String value for sorting external events
	 * @param req.query Textual query to find products that match the query
	 * @param req.lat Filters the result set by latitude. Requires lng to be set as well
	 * @param req.lng Filters the result set by longitude. Requires lat to be set as well
	 * @param req.max_distance Maximum distance in km from the lat/lng coordinates
	 * @param req.page Number of the page to retrieve
	 * @param req.page_size Number of items per page. Default value is 10
	 * @param req.near_ip When set, events near the IP address will be returned. Overrides lat/lng
	 * @param req.near_me When set, events near the callers IP address will be returned. Overrides lat/lng and near_ip
	 */
	async listExternalEvents(
		req: ExternalEventsQuery = {}
	): Promise<ExternalEventsInfo[]> {
		const query = queryString.stringify(
			req,
			{ arrayFormat: 'comma', skipNull: true, skipEmptyString: true }
		)
		const res = await this.client.get(`${this.version}/event/external?${query}`)

		return res.data.data
	}

	/**
	 * Returns queried external event
	 *
	 * @param req.id External event ID
	 * @param req.provider The name of the external provider
	 */
	async getExternalEvent(req: ProviderSpecificId): Promise<ExternalEvent> {

		const res =  await this.client.get(`${this.version}/event/external/${req.provider}/${req.id}`)

		return res.data
	}

	/**
	 * Returns available categories
	 */
	async listCategories(req: ListCategoryQuery = {}): Promise<Categories> {
		let queryWith = undefined
		if (req.with) {
			queryWith = buildQuery(req.with)
		}
		const query = queryString.stringify(
			{
				...req,
				with: queryWith,
			},
			{ arrayFormat: 'comma', skipNull: true, skipEmptyString: true }
		)
		const res = await this.client.get(`${this.version}/category?${query}`)

		return res.data
	} 
}
