<script lang="ts">
  import { getContext, onMount } from "svelte"
  import { T } from "../locales/i18n"
  import { type UIComponent, type ISelectProps, type IOption, updateProperty, type IUIComponentHandler } from "../types"
  import * as UI from ".."
  import ButtonDelete from "../libIcons/ButtonDelete.svelte"
  import ButtonAdd from "../libIcons/ButtonAdd.svelte"
  import { optionsStore, findColorOption } from "../options.js"
  import CommonSnippets from "../CommonSnippets.svelte"
  import PropsGroup from "../PropsGroup.svelte"
  import PropsListModal from "../PropsListModal.svelte"
  import { twMerge } from "tailwind-merge"

  const {
    component,
    onPropertyChange,
    forConstructor = true,
  } = $props<{
    component: UIComponent & { properties: Partial<ISelectProps> }
    onPropertyChange: (updates: Partial<{ properties?: string | object; name?: string; access?: string; eventHandler?: IUIComponentHandler }>) => void
    forConstructor?: boolean
  }>()

  const DeviceVariables = getContext<{ id: string; value: string; name: string }[]>("DeviceVariables")
  let VARIABLE_OPTIONS = $derived(DeviceVariables && Array.isArray(DeviceVariables) ? DeviceVariables : [])

  let itemsContainer: HTMLDivElement | null = $state(null)

  type ValueTypeOption = {
    id: string
    value: "text" | "number"
    name: string
    class: string
  }
  let currentValueType = $derived(
    !component.properties.options[0]
      ? ($optionsStore.SELECT_VALUE_TYPE_OPTIONS[0] as ValueTypeOption)
      : typeof component.properties.options[0].value === "number"
        ? $optionsStore.SELECT_VALUE_TYPE_OPTIONS[1]
        : ($optionsStore.SELECT_VALUE_TYPE_OPTIONS[0] as ValueTypeOption),
  )

  let Header: IOption = $derived(
    $optionsStore.HEADER_OPTIONS.find((h) => h.value === component.eventHandler.Header) ?? {
      id: "",
      name: "",
      value: "",
      class: "!w-1/4",
    },
  )

  let currentType = $derived($optionsStore.SELECT_TYPE_OPTIONS.find((t) => t.value === component.properties.type))

  const initialAlign = $derived(
    $optionsStore.TEXT_ALIGN_OPTIONS.find((a) =>
      (a.value as string).includes(component.properties.label?.class?.split(" ").find((cls: string) => cls.startsWith("text-"))),
    ),
  )
  const initialContentAlign = $derived(
    $optionsStore.TEXT_ALIGN_OPTIONS.slice(0, -1).find((a) =>
      (a.value as string).includes(component.properties.componentClass?.split(" ").find((cls: string) => cls.startsWith("text-")) ?? "text-left"),
    ),
  )

  /* Argument пуст — поле ниже лишь визуально показывает "ModCfg", реальное значение нужно проставить в состояние */
  $effect(() => {
    if (!component.eventHandler.Argument) onPropertyChange({ eventHandler: { Argument: "ModCfg" } })
  })
</script>

{#snippet SelectArgument()}
  <UI.Input
    label={{ name: $T("constructor.props.argument") }}
    value={component.eventHandler.Argument || "ModCfg"}
    maxlength={32}
    help={{ info: $T("constructor.props.argument.info"), autocomplete: "on", regExp: /^[a-zA-Z0-9\-_]{0,32}$/ }}
    onUpdate={(value) => onPropertyChange({ eventHandler: { Argument: value as string } })}
  />
{/snippet}

{#snippet SelectContentAlign()}
  <UI.Select
    label={{ name: $T("constructor.props.align.content") }}
    type="buttons"
    value={initialContentAlign}
    options={$optionsStore.TEXT_ALIGN_OPTIONS.slice(0, -1)}
    onUpdate={(option) =>
      updateProperty("componentClass", twMerge(component.properties.componentClass, (option as UI.IOption<string>).value), component, onPropertyChange)}
  />
{/snippet}

{#snippet SelectType()}
  <UI.Select
    label={{ name: $T("constructor.props.type") }}
    type="buttons"
    value={currentType}
    options={$optionsStore.SELECT_TYPE_OPTIONS}
    onUpdate={(option) => {
      if ((option as UI.IOption).value !== "buttons" && Array.isArray(component.properties.value))
        updateProperty("value", component.properties.value[0], component, onPropertyChange)

      updateProperty("type", (option as UI.IOption).value as string, component, onPropertyChange)
    }}
  />
{/snippet}

{#snippet SelectValueType()}
  <UI.Select
    wrapperClass="h-14"
    label={{ name: $T("constructor.props.valuetype") }}
    type="buttons"
    disabled={component.properties.bitMode}
    options={$optionsStore.SELECT_VALUE_TYPE_OPTIONS}
    value={currentValueType}
    onUpdate={(value) => {
      currentValueType = value as ValueTypeOption
      const options = [...(component.properties?.options || [])]
      const newType = !Array.isArray(value) ? value.value : value[0].value
      options.forEach((option) => {
        if (newType === "number") option.value = option.value !== undefined ? Number(option.value) : 0
        else option.value = option.value !== undefined ? String(option.value) : ""
      })
      updateProperty("options", options, component, onPropertyChange)
    }}
  />
{/snippet}

{#snippet SelectSettings()}
  <UI.Switch
    label={{ name: $T("constructor.props.bitMode") }}
    value={component.properties.bitMode}
    options={[{ id: crypto.randomUUID(), value: 0, class: "" }]}
    onChange={(value) => {
      updateProperty("bitMode", value, component, onPropertyChange)
      const options = [...(component.properties?.options || [])]
      const maxNumber = Math.pow(2, component.properties.range.end - component.properties.range.start + 1) - 1
      options.forEach((option) => {
        option.value = option.value !== undefined && option.value > 0 ? (option.value > maxNumber ? maxNumber : Number(option.value)) : 0
      })
      updateProperty("options", options, component, onPropertyChange)
    }}
  />

  {#if component.properties.type === "buttons" && !component.properties.bitMode}
    <UI.Switch
      label={{ name: $T("constructor.props.multiselect") }}
      value={component.properties.multiSelect}
      options={[{ id: crypto.randomUUID(), value: 0, class: "" }]}
      onChange={(value) => {
        updateProperty("multiSelect", value, component, onPropertyChange)
      }}
    />
  {/if}

  {#if component.properties.bitMode}
    <UI.Slider
      label={{ name: $T("constructor.props.range") }}
      type="range"
      number={{ minNum: 0, maxNum: 31, step: 1 }}
      value={[component.properties.range.start, component.properties.range.end]}
      onUpdate={(value) => {
        if (Array.isArray(value)) {
          updateProperty("range.start", value[0] as number, component, onPropertyChange)
          updateProperty("range.end", value[1] as number, component, onPropertyChange)
        }
      }}
    />
  {/if}
{/snippet}

{#snippet SelectOptions()}
  <PropsListModal label={$T("constructor.props.options.title")} count={component.properties.options?.length ?? 0} wrapperClass="w-200 h-[70%]">
    {#snippet main()}
      <PropsGroup>
        {#snippet headerActions()}
          <UI.Button
            wrapperClass="w-8"
            content={{ icon: ButtonAdd }}
            onClick={() => {
              const newOption: IOption = {
                id: crypto.randomUUID(),
                name: `Option ${component.properties?.options.length + 1}`,
                value: component.properties?.options.length + 1,
                class: "bg-max",
              }
              const options = [...(component.properties?.options || []), newOption]
              updateProperty("options", options, component, onPropertyChange)
            }}
          />
        {/snippet}

        <div bind:this={itemsContainer} class="flex flex-col gap-2">
          {#each component.properties.options || [] as option, index (option.id)}
            <div
              id="item-{index}"
              class="grid grid-cols-[auto_1fr_auto] items-center gap-2 rounded-lg border border-(--hairline-color) bg-(--container-color)/60 p-2"
            >
              <UI.Dragging
                wrapperClass="shrink-0"
                container={itemsContainer}
                array={component.properties.options}
                elementIndex={index}
                onUpdate={(updatedArray) => {
                  updateProperty("options", updatedArray, component, onPropertyChange)
                }}
              />
              <div class="flex flex-wrap items-end gap-2">
                <UI.Input
                  label={{ name: $T("constructor.props.optionname") }}
                  wrapperClass="min-w-28 flex-1"
                  value={option.name}
                  onUpdate={(value) => {
                    const options = [...(component.properties?.options || [])]
                    options[index]["name"] = value
                    updateProperty("options", options, component, onPropertyChange)
                  }}
                />
                <UI.Input
                  label={{ name: $T("constructor.props.optionvalue") }}
                  wrapperClass="min-w-28 flex-1"
                  value={option.value}
                  type={currentValueType.value}
                  number={component.properties.bitMode
                    ? { minNum: 0, maxNum: Math.pow(2, component.properties.range.end - component.properties.range.start + 1) - 1, step: 1 }
                    : { minNum: -1000000, maxNum: 1000000, step: 1 }}
                  onUpdate={(value) => {
                    const options = [...(component.properties?.options || [])]
                    options[index]["value"] = value
                    updateProperty("options", options, component, onPropertyChange)
                  }}
                />
                {#if forConstructor}
                  <UI.Select
                    wrapperClass="min-w-56 flex-[2]"
                    label={{ name: $T("constructor.props.colors") }}
                    type="buttons"
                    options={$optionsStore.COLOR_OPTIONS}
                    value={findColorOption($optionsStore.COLOR_OPTIONS, option.class)}
                    onUpdate={(option) => {
                      const options = [...(component.properties?.options || [])]
                      options[index]["class"] = (option as UI.IOption).value
                      updateProperty("options", options, component, onPropertyChange)
                    }}
                  />
                {:else}
                  <UI.Input
                    label={{ name: $T("constructor.props.optionclass") }}
                    wrapperClass="min-w-32 flex-[2]"
                    value={option.class}
                    onUpdate={(value) => {
                      const options = [...(component.properties?.options || [])]
                      options[index]["class"] = value as string
                      updateProperty("options", options, component, onPropertyChange)
                    }}
                  />
                {/if}
              </div>
              <UI.Button
                wrapperClass="w-8 shrink-0"
                content={{ icon: ButtonDelete }}
                onClick={() => {
                  const options = [...(component.properties?.options || [])]
                  options.splice(index, 1)
                  updateProperty("options", options, component, onPropertyChange)
                }}
              />
            </div>
          {/each}
          <div id="item-{component.properties.options.length}" class="min-h-4"></div>
        </div>
      </PropsGroup>
    {/snippet}
  </PropsListModal>
{/snippet}

{#if forConstructor}
  <div class="flex flex-col gap-2">
    <PropsGroup label={$T("constructor.props.group.general")}>
      <CommonSnippets snippet="Access" {component} {onPropertyChange} />
      <CommonSnippets snippet="Variable" {VARIABLE_OPTIONS} {component} {onPropertyChange} />
      {@render SelectArgument()}
    </PropsGroup>
    <PropsGroup label={$T("constructor.props.group.value")}>
      {@render SelectType()}
      {@render SelectValueType()}
      <CommonSnippets snippet="BitModeInfo" {component} {onPropertyChange} />
    </PropsGroup>
    <PropsGroup label={$T("constructor.props.group.appearance")}>
      <CommonSnippets snippet="Label" {component} {onPropertyChange} />
      <CommonSnippets snippet="LabelAlign" initialValue={initialAlign} {component} {onPropertyChange} />
      {@render SelectContentAlign()}
      {@render SelectSettings()}
    </PropsGroup>
  </div>
  {@render SelectOptions()}
{:else}
  <div class="flex flex-col gap-2">
    <PropsGroup label={$T("constructor.props.group.general")}>
      <CommonSnippets snippet="Identificator" {component} {onPropertyChange} />
      <CommonSnippets snippet="Access" {component} {onPropertyChange} />
      <CommonSnippets snippet="WrapperClass" {component} {onPropertyChange} />
    </PropsGroup>
    <PropsGroup label={$T("constructor.props.group.appearance")}>
      <CommonSnippets snippet="Label" {component} {onPropertyChange} />
      <CommonSnippets snippet="LabelClass" {component} {onPropertyChange} />
      {@render SelectContentAlign()}
      <CommonSnippets snippet="Disabled" {component} {onPropertyChange} />
      <CommonSnippets snippet="BitModeInfo" {component} {onPropertyChange} />
    </PropsGroup>
    <PropsGroup label={$T("constructor.props.group.value")} contentClass="items-center">
      {@render SelectType()}
      {@render SelectValueType()}
      {@render SelectSettings()}
    </PropsGroup>
  </div>

  {@render SelectOptions()}
{/if}
