import { Injectable } from '@angular/core'
import { AnyType } from '@core/types'
import { FuseNavigationItem } from '../types'

@Injectable({
	providedIn: 'root',
})
export class FuseNavigationService {
	private _componentRegistry: Map<string, AnyType> = new Map<string, AnyType>()
	private _navigationStore: Map<string, FuseNavigationItem[]> = new Map<string, AnyType>()

	registerComponent(name: string, component: AnyType): void {
		this._componentRegistry.set(name, component)
	}

	deregisterComponent(name: string): void {
		this._componentRegistry.delete(name)
	}

	getComponent<T>(name: string): T {
		return this._componentRegistry.get(name)
	}

	storeNavigation(key: string, navigation: FuseNavigationItem[]): void {
		this._navigationStore.set(key, navigation)
	}

	getNavigation(key: string): FuseNavigationItem[] {
		return this._navigationStore.get(key) ?? []
	}

	deleteNavigation(key: string): void {
		if (!this._navigationStore.has(key)) {
			console.warn(`Navigation with the key '${key}' does not exist in the store.`)
		}
		this._navigationStore.delete(key)
	}

	/** Utility function that returns a flattened version of the given navigation array */
	getFlatNavigation(navigation: FuseNavigationItem[], flatNavigation: FuseNavigationItem[] = []): FuseNavigationItem[] {
		for (const item of navigation) {
			if (item.type === 'basic') {
				flatNavigation.push(item)
				continue
			}

			if ((item.type === 'aside' || item.type === 'collapsable' || item.type === 'group') && item.children) {
				this.getFlatNavigation(item.children, flatNavigation)
			}
		}

		return flatNavigation
	}

	/** Utility function that returns the item with the given id from given navigation */
	getItem(id: string, navigation: FuseNavigationItem[]): FuseNavigationItem | null {
		for (const item of navigation) {
			if (item.id === id) {
				return item
			}

			if (item.children) {
				const childItem = this.getItem(id, item.children)

				if (childItem) {
					return childItem
				}
			}
		}

		return null
	}

	/** Utility function that returns the item's parent with the given id from given navigation */
	getItemParent(
		id: string,
		navigation: FuseNavigationItem[],
		parent: FuseNavigationItem[] | FuseNavigationItem,
	): FuseNavigationItem[] | FuseNavigationItem | null {
		for (const item of navigation) {
			if (item.id === id) {
				return parent
			}

			if (item.children) {
				const childItem = this.getItemParent(id, item.children, item)

				if (childItem) {
					return childItem
				}
			}
		}

		return null
	}
}
