<script setup>
import { Effect } from "effect";
import { computed, ref, watch } from "vue";
import { useI18n } from "vue-i18n";
import { Icon } from "@iconify/vue";
import { cel as $cel } from "../../../../../utils/cel";
import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
import { getLocalizedText } from "../../../../../share/locale";
import {
  InputGroup,
  InputGroupAddon,
  InputGroupButton,
  InputGroupInput
} from "../../../../ui/input-group";
import { useFormState } from "../../../../form/utils/state";
defineOptions({ name: "ShwfedTableTextInputRendererRuntime" });
const props = defineProps({
  column: { type: null, required: true },
  ctx: { type: Object, required: true }
});
const { locale } = useI18n();
const celContext = injectCELContext();
const formState = useFormState();
const placeholderText = computed(
  () => props.column.placeholder ? getLocalizedText(props.column.placeholder, locale.value) : void 0
);
function evalBool(expression, label) {
  if (!expression) return false;
  try {
    return Effect.runSync($cel(expression, celBindings(celContext))) === true;
  } catch (e) {
    console.error(`[shwfed-table] text-input ${label} failed`, e);
    return false;
  }
}
const isHidden = computed(() => evalBool(props.column.hidden, "hidden"));
const isDisabled = computed(() => evalBool(props.column.disabled, "disabled"));
const isReadonly = computed(() => evalBool(props.column.readonly, "readonly"));
const effectiveReadonly = computed(
  () => isReadonly.value || props.column.derived?.mode === "formula"
);
const cellValue = computed(() => {
  const v = formState.getAt(props.column.binding);
  return v == null ? "" : String(v);
});
const draft = ref(cellValue.value);
const isFocused = ref(false);
watch(cellValue, (next) => {
  if (!isFocused.value && next !== draft.value) draft.value = next;
});
function commit() {
  const next = draft.value === "" ? null : draft.value;
  if (Object.is(next, formState.getAt(props.column.binding))) return;
  formState.setAt(props.column.binding, next);
}
function onFocus() {
  isFocused.value = true;
}
function onBlur() {
  isFocused.value = false;
  commit();
}
const showClear = computed(() => !isDisabled.value && draft.value.length > 0);
function handleClear() {
  draft.value = "";
  commit();
}
</script>

<template>
  <!--
    Row budget: 2px outer inset (`p-[0.125rem]`) on each side around a 28px
    (`h-7`) input — total 32px. The inset is the deliberate gap between the
    input border and the td borders; the 28px input gives the 12px text some
    vertical breathing room. Every branch (hidden / readonly / editable) is
    sized identically so rows do not jump when a CEL condition flips. The
    default `Input` ships `h-9` + `text-base` + `md:text-sm` — we override
    each at the same breakpoint or `md:text-sm` would beat our unprefixed
    `text-[0.75rem]` and the input would render at 14px from md+ up. The
    `InputGroup`'s default border is kept on purpose (a borderless cell would
    not read as editable) but its `rounded-md` is overridden to `rounded` for
    a tighter cell look. Clear button uses `icon-xs` with an explicit `size-3`
    icon — the `icon-xs` variant does not constrain svg size on its own, so
    the iconify default would render at the parent's font-size and look
    oversized.
  -->
  <div class="p-[0.125rem] w-full">
    <span
      v-if="isHidden"
      class="block h-7 w-full"
    />
    <span
      v-else-if="effectiveReadonly"
      class="flex items-center h-7 w-full px-2 text-[0.75rem] text-zinc-700 truncate"
    >
      {{ draft || "\u2014" }}
    </span>
    <!--
      Idle border is faded to 30% so a whole grid of inputs reads as data, not
      chrome. `hover:` and `focus-within:` snap it back to full so the active
      cell stands out. `transition-colors ease-out duration-180` overrides
      `InputGroup`'s default `transition-[color,box-shadow]` to set the curve
      and timing explicitly. `data-[disabled=true]:border-zinc-100` from
      `InputGroup` still takes over for disabled, no override needed.
    -->
    <InputGroup
      v-else
      class="group/text-input h-7 rounded border-zinc-200/30 hover:border-zinc-200 focus-within:border-zinc-200 transition-colors ease-out duration-180"
    >
      <InputGroupInput
        v-model="draft"
        :placeholder="placeholderText"
        :disabled="isDisabled"
        class="h-7 text-[0.75rem] md:text-[0.75rem] px-2"
        @focus="onFocus"
        @blur="onBlur"
        @keydown.enter="commit"
      />
      <InputGroupAddon
        v-if="showClear"
        align="inline-end"
        class="[@media(hover:hover)]:opacity-0 transition-opacity group-hover/text-input:opacity-100 focus-within:opacity-100"
      >
        <InputGroupButton
          size="icon-xs"
          data-slot="text-input-clear"
          class="size-4 text-zinc-500 hover:text-zinc-700"
          tabindex="-1"
          @mousedown.prevent
          @click.stop="handleClear"
        >
          <Icon
            icon="fluent:dismiss-20-regular"
            class="size-3"
          />
        </InputGroupButton>
      </InputGroupAddon>
    </InputGroup>
  </div>
</template>
