import { createContext, JSX } from 'solid-js';
import { createStore } from "solid-js/store";
import OlFeature from 'ol/Feature';
import { BusinessDataStore } from "../businessData";

import { Stop } from '../types';
import { PositionedPanel } from '../utils';

type ByStopIdMapFeatures = Record<number, OlFeature>;

export interface SearchStore {

	getSearchText: () => string;
	setSearchText: (text: string, businessDataStore: BusinessDataStore) => Promise<void>;

	getFoundStops: () => Stop[];
	setFoundStops: (stops: Stop[]) => void;

	getDisplayedPanelId: () => number;
	setDisplayedPanelId: (panelId: number) => void;

	getPanels: () => PositionedPanel[];
	setPanels: (panels: PositionedPanel[]) => void;

	getHighlightedStop: () => Stop | undefined;
	setHighlightedStop: (stop: Stop) => void;
	resetHighlightedStop: () => void;

	enableMap: (enable: boolean) => void;
	isMapEnabled: () => boolean;
	getMapFeature: (stopId: number) => OlFeature | undefined;
	getAllMapFeatures: () => ByStopIdMapFeatures;
	setMapFeature: (stopId: number, feature: OlFeature) => void;
};

export const SearchContext = createContext<SearchStore>();


export function SearchProvider(props: { children: JSX.Element }) {

	const searchTextDelayMs = 1500;

	type Store = {
		searchText: string;
		searchPromise: Promise<void> | undefined;
		foundStops: Stop[];
		displayedPanelId: number;
		panels: PositionedPanel[];
		highlightedStop: Stop | undefined;
		mapEnabled: boolean;
		mapFeatures: ByStopIdMapFeatures;
	};

	const [store, setStore] = createStore<Store>({
		searchText: "",
		searchPromise: undefined,
		foundStops: [],
		displayedPanelId: 0,
		panels: [],
		highlightedStop: undefined,
		// mapEnabled: false,
		mapFeatures: {},
	});

	const getSearchText = (): string => {
		return store.searchText;
	}

	const debounce = async (fn: (...args: any[]) => Promise<void>, delayMs: number) => {
		let timerId: number;
		return new Promise((...args) => {
			clearTimeout(timerId);
			timerId = setTimeout(fn, delayMs, ...args);
		});
	}

	const setSearchText = async (text: string, businessDataStore: BusinessDataStore): Promise<void> => {
		setStore('searchText', text);

		if (store.searchPromise === undefined) {
			const { searchStopByName } = businessDataStore;
			const promise: Promise<void> = debounce(async (onSuccess: () => void) => {
				console.log(`Fetching data for "${store.searchText}" stop name`);
				const stopsById = await searchStopByName(store.searchText);
				console.log("stopsById=", stopsById);
				setFoundStops(Object.values(stopsById));
				onSuccess();
			}, searchTextDelayMs).then(() => {
				setStore('searchPromise', undefined);
			});
			setStore('searchPromise', promise);
		}
	}

	const getFoundStops = (): Stop[] => {
		return store.foundStops;
	}

	const setFoundStops = (stops: Stop[]): void => {
		setStore('foundStops', stops);
	}

	const getDisplayedPanelId = (): number => {
		return store.displayedPanelId;
	}

	const setDisplayedPanelId = (panelId: number): void => {
		setStore('displayedPanelId', panelId);
	}

	const getPanels = (): PositionedPanel[] => {
		return store.panels;
	}

	const setPanels = (panels: PositionedPanel[]): void => {
		setStore('panels', panels);
	}

	const getHighlightedStop = (): Stop | undefined => {
		return store.highlightedStop;
	}

	const setHighlightedStop = (stop: Stop): void => {
		setStore('highlightedStop', stop);
	}

	const resetHighlightedStop = (): void => {
		setStore('highlightedStop', undefined);
	}


	const enableMap = (enable: boolean): void => {
		setStore("mapEnabled", enable);
	}

	const isMapEnabled = (): boolean => {
		return store.mapEnabled;
	}

	const getAllMapFeatures = (): ByStopIdMapFeatures => {
		return store.mapFeatures;
	}

	const getMapFeature = (stopId: number): OlFeature | undefined => {
		return store.mapFeatures[stopId];
	}

	const setMapFeature = (stopId: number, feature: OlFeature): void => {
		setStore('mapFeatures', stopId, feature);
	};

	return (
		<SearchContext.Provider value={{
			getSearchText, setSearchText,
			getFoundStops, setFoundStops,
			getDisplayedPanelId, setDisplayedPanelId,
			getPanels, setPanels,
			getHighlightedStop, setHighlightedStop, resetHighlightedStop,
			enableMap, isMapEnabled,
			getMapFeature, getAllMapFeatures, setMapFeature,
		}}>
			{props.children}
		</SearchContext.Provider>
	);
}
