import { defineStore } from "pinia"
import { computed, ref } from "vue"

/**
 * State for a single ReactiveCanvasBuilder instance. Multiple builders
 * can coexist on a page; each is keyed by `builderId`.
 *
 * A canvas is a fixed-size positioning surface. Blocks are absolutely
 * positioned by their `x` / `y` / `width` / `height`. Block `type`
 * resolves to a Vue component at runtime via a registry the consumer
 * supplies; for the MVP we treat `type` as an opaque string and let
 * the inspector edit it.
 */

export interface ReactiveCanvasBlock {
  id: string
  type: string
  x: number
  y: number
  width: number
  height: number
  props: Record<string, unknown>
}

export interface ReactiveCanvasBuilderSchema {
  width: number
  height: number
  blocks: ReactiveCanvasBlock[]
}

/** Identifies which block is currently selected. */
export interface ReactiveCanvasBuilderSelection {
  id: string | null
}

/** Built-in block types exposed by the palette in the MVP. */
export const REACTIVE_CANVAS_BLOCK_TYPES = [
  "text-block",
  "image-block",
  "button-block",
  "spacer-block",
  "container-block",
] as const

export type ReactiveCanvasBlockType =
  (typeof REACTIVE_CANVAS_BLOCK_TYPES)[number]

const DEFAULT_CANVAS_WIDTH = 800
const DEFAULT_CANVAS_HEIGHT = 600
const DEFAULT_BLOCK_WIDTH = 160
const DEFAULT_BLOCK_HEIGHT = 80

let idCounter = 0
function nextId(prefix: string): string {
  idCounter += 1
  return `${prefix}-${Date.now()}-${idCounter}`
}

/** Test helper to make ids deterministic. */
export function __resetReactiveCanvasBuilderIdCounter(): void {
  idCounter = 0
}

function emptySchema(): ReactiveCanvasBuilderSchema {
  return {
    width: DEFAULT_CANVAS_WIDTH,
    height: DEFAULT_CANVAS_HEIGHT,
    blocks: [],
  }
}

function defaultPropsForType(type: string): Record<string, unknown> {
  switch (type) {
    case "text-block":
      return { text: "Sample text" }
    case "image-block":
      return { src: "", alt: "" }
    case "button-block":
      return { label: "Click me", action: "" }
    case "spacer-block":
      return {}
    case "container-block":
      return { padding: 8 }
    default:
      return {}
  }
}

export const useReactiveCanvasBuilderStore = defineStore(
  "gx-modui/reactiveCanvasBuilder",
  () => {
    const builders = ref<Record<string, ReactiveCanvasBuilderSchema>>({})
    const selections = ref<
      Record<string, ReactiveCanvasBuilderSelection>
    >({})

    function ensureBuilder(builderId: string): ReactiveCanvasBuilderSchema {
      if (!builders.value[builderId]) {
        builders.value[builderId] = emptySchema()
        selections.value[builderId] = { id: null }
      }
      return builders.value[builderId]!
    }

    function loadSchema(
      builderId: string,
      schema: ReactiveCanvasBuilderSchema,
    ): void {
      builders.value[builderId] = {
        width: schema.width,
        height: schema.height,
        blocks: schema.blocks.map((b) => ({ ...b, props: { ...b.props } })),
      }
      selections.value[builderId] = { id: null }
    }

    function resetBuilder(builderId: string): void {
      delete builders.value[builderId]
      delete selections.value[builderId]
    }

    /** Append a new block of `type` and return its id. */
    function addBlock(builderId: string, type: string): string {
      const schema = ensureBuilder(builderId)
      const id = nextId(`block-${type}`)
      schema.blocks = [
        ...schema.blocks,
        {
          id,
          type,
          x: 16,
          y: 16,
          width: DEFAULT_BLOCK_WIDTH,
          height: DEFAULT_BLOCK_HEIGHT,
          props: defaultPropsForType(type),
        },
      ]
      return id
    }

    function removeBlock(builderId: string, blockId: string): void {
      const schema = ensureBuilder(builderId)
      schema.blocks = schema.blocks.filter((b) => b.id !== blockId)
      const sel = selections.value[builderId]
      if (sel?.id === blockId) {
        selections.value[builderId] = { id: null }
      }
    }

    function updateBlock(
      builderId: string,
      blockId: string,
      patch: Partial<Omit<ReactiveCanvasBlock, "id">>,
    ): void {
      const schema = ensureBuilder(builderId)
      const idx = schema.blocks.findIndex((b) => b.id === blockId)
      if (idx < 0) {
        return
      }
      const current = schema.blocks[idx]!
      const list = [...schema.blocks]
      list[idx] = { ...current, ...patch }
      schema.blocks = list
    }

    function setCanvasSize(
      builderId: string,
      patch: { width?: number; height?: number },
    ): void {
      const schema = ensureBuilder(builderId)
      if (patch.width !== undefined) {
        schema.width = patch.width
      }
      if (patch.height !== undefined) {
        schema.height = patch.height
      }
    }

    function select(builderId: string, id: string | null): void {
      selections.value[builderId] = { id }
    }

    function getSelection(
      builderId: string,
    ): ReactiveCanvasBuilderSelection {
      return selections.value[builderId] ?? { id: null }
    }

    function getSchema(builderId: string): ReactiveCanvasBuilderSchema {
      return ensureBuilder(builderId)
    }

    return {
      builders,
      selections,
      ensureBuilder,
      loadSchema,
      resetBuilder,
      addBlock,
      removeBlock,
      updateBlock,
      setCanvasSize,
      select,
      getSelection,
      getSchema,
    }
  },
)

/** Composable wrapper around `useReactiveCanvasBuilderStore`. */
export function useReactiveCanvasBuilder(builderId: string) {
  const store = useReactiveCanvasBuilderStore()
  store.ensureBuilder(builderId)
  return {
    schema: computed<ReactiveCanvasBuilderSchema>(() =>
      store.getSchema(builderId),
    ),
    selection: computed<ReactiveCanvasBuilderSelection>(() =>
      store.getSelection(builderId),
    ),
    addBlock: (type: string) => store.addBlock(builderId, type),
    removeBlock: (id: string) => store.removeBlock(builderId, id),
    updateBlock: (
      id: string,
      patch: Partial<Omit<ReactiveCanvasBlock, "id">>,
    ) => store.updateBlock(builderId, id, patch),
    setCanvasSize: (patch: { width?: number; height?: number }) =>
      store.setCanvasSize(builderId, patch),
    select: (id: string | null) => store.select(builderId, id),
    loadSchema: (schema: ReactiveCanvasBuilderSchema) =>
      store.loadSchema(builderId, schema),
    reset: () => store.resetBuilder(builderId),
  }
}
