<script setup lang="ts">
import { defineAsyncComponent, ref, watch } from "vue";
import { usePage } from "@inertiajs/vue3";
const DynamicField = defineAsyncComponent(
  () => import("@/components/DynamicField.vue"),
);
import Button from "@/components/ui/Button.vue";
import type { FieldDefinition } from "./types";

type Row = Record<string, unknown> & { _key: number };

const props = defineProps<{
  field: FieldDefinition;
  modelValue?: unknown;
  error?: string;
}>();

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

const page = usePage();
let keyCounter = 0;

function makeRow(data: Record<string, unknown> = {}): Row {
  return { ...data, _key: keyCounter++ };
}

function toRows(value: unknown): Row[] {
  if (!Array.isArray(value)) {
    return [];
  }
  return value.map((item) =>
    makeRow(
      typeof item === "object" && item !== null
        ? (item as Record<string, unknown>)
        : {},
    ),
  );
}

const rows = ref<Row[]>(toRows(props.modelValue));

watch(
  () => props.modelValue,
  (value) => {
    if (!Array.isArray(value)) {
      rows.value = [];
      return;
    }
    // Reuse existing _key values by position so Vue keeps DOM nodes alive
    // and focused inputs don't lose focus on every keystroke.
    rows.value = value.map((item, i) => {
      const data =
        typeof item === "object" && item !== null
          ? (item as Record<string, unknown>)
          : {};
      const existingKey = rows.value[i]?._key;
      return existingKey !== undefined
        ? { ...data, _key: existingKey }
        : makeRow(data);
    });
  },
);

function emitRows(): void {
  emit(
    "update:modelValue",
    rows.value.map(({ _key: _, ...rest }) => rest),
  );
}

function addRow(): void {
  const defaults: Record<string, unknown> = {};
  for (const subField of props.field.fields ?? []) {
    defaults[subField.name] = subField.default ?? null;
  }
  rows.value = [...rows.value, makeRow(defaults)];
  emitRows();
}

function removeRow(index: number): void {
  rows.value = rows.value.filter((_, i) => i !== index);
  emitRows();
}

function moveUp(index: number): void {
  if (index === 0) return;
  const next = [...rows.value];
  [next[index - 1], next[index]] = [next[index], next[index - 1]];
  rows.value = next;
  emitRows();
}

function moveDown(index: number): void {
  if (index === rows.value.length - 1) return;
  const next = [...rows.value];
  [next[index], next[index + 1]] = [next[index + 1], next[index]];
  rows.value = next;
  emitRows();
}

function updateCell(rowIndex: number, fieldName: string, value: unknown): void {
  rows.value = rows.value.map((row, i) => {
    if (i !== rowIndex) return row;
    return { ...row, [fieldName]: value };
  });
  emitRows();
}

function rowError(rowIndex: number, fieldName: string): string | undefined {
  const errors = (page.props as Record<string, unknown>).errors as
    | Record<string, string>
    | undefined;
  if (!errors) return undefined;
  return errors[`${props.field.name}.${rowIndex}.${fieldName}`];
}

const isAtMax = () =>
  props.field.maxRows != null && rows.value.length >= props.field.maxRows;
</script>

<template>
  <div class="space-y-3">
    <!-- Label -->
    <label class="inline-flex items-center text-sm font-medium text-foreground">
      {{ field.label }}
    </label>

    <!-- Error for the repeater itself -->
    <p v-if="error" class="text-sm text-destructive">{{ error }}</p>

    <!-- Rows -->
    <div
      v-for="(row, rowIndex) in rows"
      :key="row._key"
      class="rounded-md border border-border bg-muted/30 p-4 space-y-4"
    >
      <!-- Row header with controls -->
      <div class="flex items-center justify-between">
        <span
          class="text-xs font-medium text-muted-foreground uppercase tracking-wide"
        >
          #{{ rowIndex + 1 }}
        </span>
        <div class="flex items-center gap-1">
          <button
            type="button"
            :disabled="rowIndex === 0"
            class="inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent disabled:opacity-30 disabled:pointer-events-none transition-colors"
            @click="moveUp(rowIndex)"
          >
            <svg
              class="h-3.5 w-3.5"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              stroke-width="2.5"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                d="M5 15l7-7 7 7"
              />
            </svg>
          </button>
          <button
            type="button"
            :disabled="rowIndex === rows.length - 1"
            class="inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent disabled:opacity-30 disabled:pointer-events-none transition-colors"
            @click="moveDown(rowIndex)"
          >
            <svg
              class="h-3.5 w-3.5"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              stroke-width="2.5"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                d="M19 9l-7 7-7-7"
              />
            </svg>
          </button>
          <button
            type="button"
            class="inline-flex h-7 w-7 items-center justify-center rounded text-muted-foreground hover:text-destructive hover:bg-destructive/10 transition-colors"
            @click="removeRow(rowIndex)"
          >
            <svg
              class="h-3.5 w-3.5"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
              stroke-width="2.5"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                d="M6 18L18 6M6 6l12 12"
              />
            </svg>
          </button>
        </div>
      </div>

      <!-- Sub-fields -->
      <DynamicField
        v-for="subField in field.fields ?? []"
        :key="subField.name"
        :field="{
          ...subField,
          name: `${field.name}_${rowIndex}_${subField.name}`,
        }"
        :model-value="row[subField.name]"
        :error="rowError(rowIndex, subField.name)"
        @update:model-value="updateCell(rowIndex, subField.name, $event)"
      />
    </div>

    <!-- Empty state -->
    <p
      v-if="rows.length === 0"
      class="rounded-md border border-dashed border-border py-6 text-center text-sm text-muted-foreground"
    >
      No items yet. Click "Add" to create the first one.
    </p>

    <!-- Add button -->
    <Button
      type="button"
      variant="outline"
      size="sm"
      :disabled="isAtMax()"
      @click="addRow"
    >
      <svg
        class="mr-1.5 h-3.5 w-3.5"
        fill="none"
        viewBox="0 0 24 24"
        stroke="currentColor"
        stroke-width="2.5"
      >
        <path
          stroke-linecap="round"
          stroke-linejoin="round"
          d="M12 4v16m8-8H4"
        />
      </svg>
      Add
    </Button>
  </div>
</template>
