<script setup lang="ts">
import { computed, defineAsyncComponent, type Component } from "vue";
import { registry } from "../registry";
import InputGroup from "./ui/InputGroup.vue";
import TextInput from "./fields/TextInput.vue";
import EmailInput from "./fields/EmailInput.vue";
import TelInput from "./fields/TelInput.vue";
import UrlInput from "./fields/UrlInput.vue";
import NumberInput from "./fields/NumberInput.vue";
import PasswordInput from "./fields/PasswordInput.vue";
import TextareaInput from "./fields/TextareaInput.vue";
import RadioInput from "./fields/RadioInput.vue";
import CheckboxInput from "./fields/CheckboxInput.vue";
import ToggleInput from "./fields/ToggleInput.vue";
import HiddenInput from "./fields/HiddenInput.vue";
import DatepickerInput from "./fields/DatepickerInput.vue";
import DatetimeInput from "./fields/DatetimeInput.vue";
import type { FieldDefinition } from "./fields/types";

// Lazy-loaded: break circular deps (SelectInput/Repeater→DynamicField) and
// avoid pulling Tiptap, qrcode, and Sheet code into the initial bundle.
const SelectInput = defineAsyncComponent(
  () => import("./fields/SelectInput.vue"),
);
const MfaSettings = defineAsyncComponent(
  () => import("./fields/MfaSettings.vue"),
);
const WysiwygInput = defineAsyncComponent(
  () => import("./fields/WysiwygInput.vue"),
);
const RelatedInput = defineAsyncComponent(
  () => import("./fields/RelatedInput.vue"),
);
const RepeaterInput = defineAsyncComponent(
  () => import("./fields/RepeaterInput.vue"),
);
const NestedResourceEditor = defineAsyncComponent(
  () => import("./fields/NestedResourceEditor.vue"),
);

const builtinMap: Record<string, Component> = {
  TextInput,
  EmailInput,
  TelInput,
  UrlInput,
  NumberInput,
  PasswordInput,
  TextareaInput,
  SelectInput,
  RadioInput,
  CheckboxInput,
  ToggleInput,
  HiddenInput,
  DatepickerInput,
  DatetimeInput,
  MfaSettings,
  WysiwygInput,
  RelatedInput,
  RepeaterInput,
  NestedResourceEditor,
};

const { field, currentLocale } = defineProps<{
  field: FieldDefinition;
  modelValue: unknown;
  error?: string;
  currentLocale?: string | null;
}>();

defineEmits<{
  "update:modelValue": [value: unknown];
}>();

const resolvedComponent = computed<Component | null>(() => {
  // Try module registry first (e.g. 'MediaSelector' from builder-media)
  const fromRegistry = registry.resolveComponent(field.component);
  if (fromRegistry) return fromRegistry;

  // Try built-in component map
  const fromBuiltin = builtinMap[field.component];
  if (fromBuiltin) return fromBuiltin;

  console.error(
    `[Builder] Unknown field component "${field.component}" for field "${field.name}". ` +
      `Is the module that provides this component registered?`,
  );

  return null;
});

const isHidden = computed(() => field.component === "HiddenInput");

// These components manage their own internal structure — skip InputGroup + outer label.
const isFullWidth = computed(() =>
  [
    "FieldBlockEditor",
    "FieldSeoInput",
    "RepeaterInput",
    "NestedResourceEditor",
  ].includes(field.component),
);

// Toggle and checkbox render their own inline labels — skip the outer label
// to prevent browsers from firing two click events (label activation + button activation).
const skipLabel = computed(() =>
  ["ToggleInput", "CheckboxInput"].includes(field.component),
);
</script>

<template>
  <!-- Unknown component — emit error, render placeholder -->
  <div
    v-if="resolvedComponent === null"
    class="rounded border border-destructive/40 bg-destructive/10 px-3 py-2 text-sm text-destructive"
  >
    Unknown field component: {{ field.component }}
  </div>

  <InputGroup
    v-else-if="!isHidden && !isFullWidth"
    :field-id="field.name"
    :error="error"
    :hint="field.hint ?? undefined"
  >
    <template #default>
      <label
        v-if="!skipLabel"
        :for="field.name"
        class="inline-flex items-center text-sm font-medium text-foreground"
      >
        {{ field.label }}
        <span
          v-if="field.rules.includes('required')"
          class="ml-0.5 text-destructive"
          >*</span
        >
        <span
          v-if="field.translatable && currentLocale"
          class="ml-1.5 rounded px-1.5 py-0.5 text-xs uppercase tracking-wide bg-muted text-muted-foreground"
        >
          {{ currentLocale }}
        </span>
      </label>

      <component
        :is="resolvedComponent"
        :field="field"
        :model-value="modelValue"
        :error="error"
        :current-locale="currentLocale"
        @update:model-value="$emit('update:modelValue', $event)"
      />
    </template>
  </InputGroup>

  <!-- Hidden fields render without wrapper -->
  <component
    v-else-if="isHidden"
    :is="resolvedComponent"
    :field="field"
    :model-value="modelValue"
    :error="error"
    :current-locale="currentLocale"
    @update:model-value="$emit('update:modelValue', $event)"
  />

  <!-- Full-width fields (e.g. FieldBlockEditor) render without InputGroup -->
  <component
    v-else
    :is="resolvedComponent"
    :field="field"
    :model-value="modelValue"
    :error="error"
    :current-locale="currentLocale"
    @update:model-value="$emit('update:modelValue', $event)"
  />
</template>
