import type { InjectionKey, Plugin } from 'vue'
import type { ComponentProps } from 'vue-component-type-helpers'
import type { ConfirmModalUserOptions, ModalComponentProps, ModalConfirmOptions, ModalFormComponentProps, ModalFormOptions, ModalOptions, ModalType } from './modalTypes'
import { Modal, ModalConfirm, ModalForm } from '@bagelink/vue'
import { defineComponent, h, inject } from 'vue'

export interface ModalApi {
	showModal: <T extends { [key: string]: any }>(options: ModalOptions, slots?: { [key: string]: any }) => ModalComponentProps<T> | undefined
	showModalForm: <T extends { [key: string]: any }>(options: ModalFormOptions<T>, slots?: { [key: string]: any }) => ModalFormComponentProps<T> | undefined
	hideModal: (index?: number) => void
	confirmModal: (options: ConfirmModalUserOptions) => Promise<boolean>
}

export const ModalSymbol: InjectionKey<ModalApi> = Symbol('modal')

export function useModal(): ModalApi {
	const modalApi = inject(ModalSymbol)
	if (!modalApi) throw new Error('Modal API not provided')
	return modalApi
}

export const ModalPlugin: Plugin = {
	install: (app) => {
		const modalStack = $ref<ModalComponentProps<object>[]>([])

		const hideModal = (index: number) => {
			modalStack.splice(index, 1)
		}

		const confirmModal = (options: ConfirmModalUserOptions): Promise<boolean> => {
			return new Promise((resolve) => {
				const confirmOptions = typeof options === 'string' ? { title: '', message: options } : options
				modalStack.push({
					modalOptions: { ...confirmOptions, resolve },
					modalType: 'confirmModal',
					componentSlots: {},
				})
			})
		}

		const showModal = <T extends { [key: string]: any }>(
			modalType: ModalType,
			options: ModalOptions | ModalFormOptions<T>,
			slots: { [key: string]: any } = {}
		): ModalComponentProps<T> | ModalFormComponentProps<T> | undefined => {
			const modalComponent = {
				modalOptions: options,
				modalType,
				componentSlots: slots,
			}
			modalStack.push(modalComponent)

			if (modalType === 'modalForm') {
				return modalComponent as ModalFormComponentProps<T>
			}
			return modalComponent
		}

		app.provide(ModalSymbol, {
			showModal: (options: ModalOptions, slots?: { [key: string]: any }) => showModal('modal', options, slots),

			showModalForm: <T extends { [key: string]: any }>(options: ModalFormOptions<T>, slots?: { [key: string]: any }) => showModal<T>('modalForm', options, slots) as ModalFormComponentProps<T>,

			confirmModal: (options: ConfirmModalUserOptions) => confirmModal(options),

			hideModal: (index = modalStack.length - 1) => { hideModal(index) },
		})

		const ModalComponent = defineComponent({
			data: () => ({ modalStack }),
			render() {
				return this.modalStack.map((modal, index) => {
					const props = {
						...modal.modalOptions,
						'visible': true,
						'onUpdate:visible': () => { hideModal(index) },
					}
					switch (modal.modalType) {
						case 'modalForm':
							return h(ModalForm, props as ComponentProps<typeof ModalForm>, modal.componentSlots)
						case 'confirmModal':

							return h(ModalConfirm, props as ModalConfirmOptions, {})
						default:
							return h(Modal, props, modal.componentSlots)
					}
				})
			},
		})
		app.component('ModalContainer', ModalComponent)
	},
}
