import { mount, unmount, type Component, type SvelteComponent } from "svelte"
import { apiBaseOverride } from "./lib/store"
import BlockRenderer from "./blocks/BlockRenderer.svelte"

const previewCssUrl = new URL("./index.css", import.meta.url).toString()

type BlockRenderContext = {
    namespace?: string
    apiBase?: string
    projectBase?: string
}

type BlockHandle = {
    update(row: Record<string, any>, context?: BlockRenderContext): void
    destroy(): void
}

type BlockDefinition = {
    render(container: HTMLElement | ShadowRoot, row: Record<string, any>, context?: BlockRenderContext): BlockHandle
    css?: string[]
    previewStyles?: Record<string, string>
    label?: string
    icon?: string
    color?: string
}

type BlockPresentation = {
    label: string
    icon: string
    color: string
}

function getAdminPreviewProps(props?: { [key: string]: any }) {
    return {
        isAdminPreview: true,
        ...(props || {}),
    }
}

function getRenderedElement(
    component: typeof SvelteComponent,
    options?: { props: { [key: string]: any }; addCss?: string[] },
    nestedElements?: { tagName: string; className?: string }[]
) {
    const el = document.createElement("div")
    el.attachShadow({ mode: "open" })

    const body = document.createElement("body")

    // build nested divs with css classes
    let target: HTMLElement = body
    nestedElements?.forEach((e) => {
        const newElement = document.createElement(e.tagName)
        if (e.className) {
            newElement.className = e.className
        }
        target.appendChild(newElement)
        target = newElement
    })

    el.shadowRoot.appendChild(body)

    options?.addCss?.forEach((css) => {
        const link = document.createElement("link")
        link.rel = "stylesheet"
        link.href = css
        link.type = "text/css"
        el.shadowRoot.appendChild(link)
    })

    new component({
        target: target,
        props: getAdminPreviewProps(options?.props),
    })

    return el
}

function createContentBlockDefinition(presentation: BlockPresentation): BlockDefinition {
    return {
        css: [previewCssUrl],
        label: presentation.label,
        icon: presentation.icon,
        color: presentation.color,
        previewStyles: {
            "background-color": "white",
            position: "relative",
        },
        render(container, row, context) {
            const previewApiBase = context?.projectBase || context?.apiBase
            if (previewApiBase) {
                apiBaseOverride.set(String(previewApiBase))
            }

            const target = document.createElement("div")
            target.dataset.adminPreview = "true"
            container.appendChild(target)

            let mountedComponent = mount(BlockRenderer as Component<any>, {
                target,
                props: {
                    blocks: [row as ContentBlockEntry],
                    isAdminPreview: true,
                },
            })

            return {
                update(nextRow, nextContext) {
                    const nextPreviewApiBase = nextContext?.projectBase || nextContext?.apiBase
                    if (nextPreviewApiBase) {
                        apiBaseOverride.set(String(nextPreviewApiBase))
                    }

                    unmount(mountedComponent)
                    target.innerHTML = ""
                    mountedComponent = mount(BlockRenderer as Component<any>, {
                        target,
                        props: {
                            blocks: [nextRow as ContentBlockEntry],
                            isAdminPreview: true,
                        },
                    })
                },
                destroy() {
                    unmount(mountedComponent)
                    target.remove()
                },
            }
        },
    }
}

const blockRegistry = {
    hero: createContentBlockDefinition({ label: "Hero", icon: "image", color: "#1d4ed8" }),
    features: createContentBlockDefinition({ label: "Features", icon: "view_quilt", color: "#0f766e" }),
    richtext: createContentBlockDefinition({ label: "Richtext", icon: "article", color: "#7c3aed" }),
    accordion: createContentBlockDefinition({ label: "Accordion", icon: "expand", color: "#b45309" }),
    "contact-form": createContentBlockDefinition({
        label: "Contact Form",
        icon: "mail",
        color: "#be185d",
    }),
}

export {
    getAdminPreviewProps,
    getRenderedElement,
    blockRegistry,
    // pass also required svelte components here
}
