import type { EmblaCarouselSvelteType } from 'embla-carousel-svelte';
import type emblaCarouselSvelte from 'embla-carousel-svelte';
import { getContext, hasContext, setContext } from 'svelte';
import type { HTMLAttributes } from 'svelte/elements';
import type { Readable, Writable } from 'svelte/store';

export type CarouselAPI =
	NonNullable<NonNullable<EmblaCarouselSvelteType['$$_attributes']>['on:emblaInit']> extends (
		evt: CustomEvent<infer CarouselAPI>
	) => void
		? CarouselAPI
		: never;

type EmblaCarouselConfig = NonNullable<Parameters<typeof emblaCarouselSvelte>[1]>;

export type CarouselOptions = EmblaCarouselConfig['options'];
export type CarouselPlugins = EmblaCarouselConfig['plugins'];

////

export type CarouselProps = {
	opts?: CarouselOptions;
	plugins?: CarouselPlugins;
	api?: CarouselAPI;
	orientation?: 'horizontal' | 'vertical';
} & HTMLAttributes<HTMLDivElement>;

const EMBLA_CAROUSEL_CONTEXT = Symbol('EMBLA_CAROUSEL_CONTEXT');

type EmblaContext = {
	api: Writable<CarouselAPI | undefined>;
	orientation: Writable<'horizontal' | 'vertical'>;
	scrollNext: () => void;
	scrollPrev: () => void;
	canScrollNext: Readable<boolean>;
	canScrollPrev: Readable<boolean>;
	handleKeyDown: (e: KeyboardEvent) => void;
	options: Writable<CarouselOptions>;
	plugins: Writable<CarouselPlugins>;
	onInit: (e: CustomEvent<CarouselAPI>) => void;
	scrollTo: (index: number, jump?: boolean) => void;
	scrollSnaps: Readable<number[]>;
	selectedIndex: Readable<number>;
};

export function setEmblaContext(config: EmblaContext): EmblaContext {
	setContext(EMBLA_CAROUSEL_CONTEXT, config);
	return config;
}

export function getEmblaContext(name = 'This component') {
	if (!hasContext(EMBLA_CAROUSEL_CONTEXT)) {
		throw new Error(`${name} must be used within a <Carousel.Root> component`);
	}
	return getContext<ReturnType<typeof setEmblaContext>>(EMBLA_CAROUSEL_CONTEXT);
}
