<script setup lang="ts">
import { computed, watch } from "vue";
import { router, Link } from "@inertiajs/vue3";
import Button from "../../components/ui/Button.vue";
import Dialog from "../../components/ui/Dialog.vue";
import DialogContent from "../../components/ui/DialogContent.vue";
import DialogHeader from "../../components/ui/DialogHeader.vue";
import DialogFooter from "../../components/ui/DialogFooter.vue";
import DialogTitle from "../../components/ui/DialogTitle.vue";
import DialogDescription from "../../components/ui/DialogDescription.vue";
import { ref } from "vue";
import BulkEditSheet from "../../components/BulkEditSheet.vue";
import LocaleSwitcher from "../../components/LocaleSwitcher.vue";
import Pagination from "../../components/Pagination.vue";
import ResourceIndexToolbar from "../../components/ResourceIndexToolbar.vue";
import ResourceTable from "../../components/ResourceTable.vue";
import SettingsTabBar from "../../components/SettingsTabBar.vue";
import { useTranslations } from "../../composables/useTranslations";
import { useBuilderPrefix } from "../../composables/useBuilderPrefix";
import { useTableState } from "../../composables/useTableState";
import { useBulkSelection } from "../../composables/useBulkSelection";
import { useBulkEdit } from "../../composables/useBulkEdit";
import { useColumnVisibility } from "../../composables/useColumnVisibility";
import type { FieldDefinition } from "../../components/fields/types";
import type {
  Language,
  Column,
  Paginator,
  PaginationLink,
  ResourceDefinition,
} from "../../types";

const { t } = useTranslations();
const prefix = useBuilderPrefix();

const props = defineProps<{
  resource: ResourceDefinition;
  records: Paginator | Record<string, unknown>[];
  currentLocale: string | null;
  availableLocales: Language[];
}>();

const {
  searchQuery,
  sortColumn,
  sortDirection,
  activeFilters,
  perPage,
  navigate,
  toggleSort,
  setFilter,
  setPerPage,
} = useTableState(
  props.resource.slug,
  props.resource.filters,
  props.currentLocale,
);

let searchTimer: ReturnType<typeof setTimeout> | null = null;
watch(searchQuery, (val) => {
  if (searchTimer) clearTimeout(searchTimer);
  searchTimer = setTimeout(() => navigate({ search: val || undefined }), 300);
});

const isPaginated = computed(
  () => !Array.isArray(props.records) && "data" in props.records,
);
const rows = computed<Record<string, unknown>[]>(() =>
  isPaginated.value
    ? (props.records as Paginator).data
    : (props.records as Record<string, unknown>[]),
);
const paginatorLinks = computed<PaginationLink[]>(() =>
  isPaginated.value ? (props.records as Paginator).links : [],
);
const paginatorTotal = computed(() =>
  isPaginated.value ? (props.records as Paginator).total : rows.value.length,
);

const resourceFields = computed<FieldDefinition[]>(() =>
  props.resource.sections.flatMap((s) => s.fields),
);

const allColumns = computed<Column[]>(() => {
  if (props.resource.columns.length > 0) {
    return props.resource.columns;
  }
  return resourceFields.value.map((f) => ({
    key: f.name,
    label: f.label,
    sortable: false,
    searchable: false,
    component: null,
    hidden: false,
    badges: null,
  }));
});

const { hiddenColumns, visibleColumns, toggleColumn, resetVisibility } =
  useColumnVisibility(props.resource.slug, allColumns);

const hasLocales = computed(() => props.availableLocales.length > 1);

const canEdit = computed(() => {
  const perms = props.resource.actionPermissions ?? {};
  return !("update" in perms) || perms.update !== null;
});

const {
  selectedIds,
  allSelected,
  isSelectAllRecords,
  toggle: toggleRow,
  toggleAll,
  selectAllRecords,
  clear: clearSelection,
} = useBulkSelection(rows);

const selectionCount = computed(() =>
  isSelectAllRecords.value ? paginatorTotal.value : selectedIds.value.size,
);

const hasSelection = computed(
  () => selectedIds.value.size > 0 || isSelectAllRecords.value,
);

const activeFilterCount = computed(
  () =>
    Object.values(activeFilters.value).filter((v) => v !== "" && v != null)
      .length,
);

function clearFilters(): void {
  for (const filter of props.resource.filters) {
    setFilter(filter.key, "");
  }
}

const {
  bulkEditSheetOpen,
  editableFields,
  bulkEditForm,
  openBulkEdit,
  executeBulkEdit,
} = useBulkEdit(
  props.resource.slug,
  resourceFields,
  selectedIds,
  isSelectAllRecords,
  searchQuery,
  activeFilters,
  props.currentLocale,
  prefix,
  clearSelection,
);

// Delete dialog (single record or bulk)
const deleteDialog = ref<{ open: boolean; recordId: unknown; isBulk: boolean }>(
  { open: false, recordId: null, isBulk: false },
);

function deleteRecord(id: unknown): void {
  deleteDialog.value = { open: true, recordId: id, isBulk: false };
}

function openBulkDelete(): void {
  deleteDialog.value = { open: true, recordId: null, isBulk: true };
}

function executeDelete(): void {
  if (deleteDialog.value.isBulk) {
    const payload: Record<string, unknown> = { action: "delete" };
    if (props.currentLocale) payload.locale = props.currentLocale;
    if (isSelectAllRecords.value) {
      payload.select_all = true;
      if (searchQuery.value) payload.search = searchQuery.value;
      if (Object.keys(activeFilters.value).length > 0) {
        payload.filters = activeFilters.value;
      }
    } else {
      payload.ids = Array.from(selectedIds.value);
    }

    const deletedIds = isSelectAllRecords.value
      ? null
      : Array.from(selectedIds.value);

    router.post(`/${prefix}/${props.resource.slug}/bulk`, payload, {
      optimistic: (pageProps) => {
        const records = pageProps.records as
          | Paginator
          | Record<string, unknown>[];
        if (Array.isArray(records)) {
          return {
            records: deletedIds
              ? records.filter((r) => !deletedIds.includes(r.id))
              : [],
          };
        }
        const paginator = records as Paginator;
        return {
          records: {
            ...paginator,
            data: deletedIds
              ? paginator.data.filter((r) => !deletedIds.includes(r.id))
              : [],
            total: deletedIds
              ? Math.max(0, paginator.total - deletedIds.length)
              : 0,
          },
        };
      },
    });
    clearSelection();
  } else if (deleteDialog.value.recordId !== null) {
    const id = deleteDialog.value.recordId;
    const localeParam = props.currentLocale
      ? `?locale=${props.currentLocale}`
      : "";
    router.delete(`/${prefix}/${props.resource.slug}/${id}${localeParam}`, {
      optimistic: (pageProps) => {
        const records = pageProps.records as
          | Paginator
          | Record<string, unknown>[];
        if (Array.isArray(records)) {
          return {
            records: records.filter((r) => r.id !== id),
          };
        }
        const paginator = records as Paginator;
        return {
          records: {
            ...paginator,
            data: paginator.data.filter((r) => r.id !== id),
            total: Math.max(0, paginator.total - 1),
          },
        };
      },
    });
  }
  deleteDialog.value.open = false;
}

function editRecord(id: unknown): void {
  const params: Record<string, string> = {};
  if (props.currentLocale) params.locale = props.currentLocale;
  router.get(`/${prefix}/${props.resource.slug}/${id}/edit`, params);
}

function goToPage(url: string | null): void {
  if (!url) return;
  router.get(url, {}, { preserveState: true });
}

const exportUrl = computed(() => {
  const params = new URLSearchParams();
  if (searchQuery.value) params.set("search", searchQuery.value);
  for (const [k, v] of Object.entries(activeFilters.value)) {
    if (v) params.set(k, v);
  }
  if (sortColumn.value) params.set("column", sortColumn.value);
  if (sortDirection.value !== "asc")
    params.set("direction", sortDirection.value);
  const qs = params.toString();
  return `/${prefix}/${props.resource.slug}/export${qs ? "?" + qs : ""}`;
});
</script>

<template>
  <!-- Row delete dialog -->
  <Dialog v-model:open="deleteDialog.open">
    <DialogContent>
      <DialogHeader>
        <DialogTitle>
          {{ t("builder.resources.delete_confirm_title") }}
        </DialogTitle>
        <DialogDescription>
          {{ t("builder.resources.delete_confirm_message") }}
        </DialogDescription>
      </DialogHeader>
      <DialogFooter>
        <Button variant="outline" @click="deleteDialog.open = false">
          {{ t("builder.resources.cancel") }}
        </Button>
        <Button variant="destructive" @click="executeDelete()">
          {{ t("builder.resources.delete") }}
        </Button>
      </DialogFooter>
    </DialogContent>
  </Dialog>

  <!-- Bulk edit sheet -->
  <BulkEditSheet
    v-model:open="bulkEditSheetOpen"
    :editable-fields="editableFields"
    :bulk-edit-form="bulkEditForm"
    :selection-count="selectionCount"
    @update:bulk-edit-form="(key, val) => (bulkEditForm[key] = val)"
    @save="executeBulkEdit()"
  />

  <!-- Page header -->
  <div class="mb-6 flex items-center justify-between">
    <h1 class="text-2xl font-semibold tracking-tight">
      {{ resource.label }}
    </h1>
    <div class="flex items-center gap-3">
      <LocaleSwitcher
        v-if="hasLocales"
        :current-locale="currentLocale"
        :languages="availableLocales"
        :on-switch="(code) => navigate({ locale: code })"
      />
      <Button as-child>
        <Link
          :href="`/${prefix}/${resource.slug}/create${currentLocale ? '?locale=' + currentLocale : ''}`"
        >
          {{
            t("builder.resources.create_title", {
              label: resource.singularLabel.toLowerCase(),
            })
          }}
        </Link>
      </Button>
    </div>
  </div>

  <SettingsTabBar />

  <ResourceIndexToolbar
    :filters="resource.filters"
    :all-columns="allColumns"
    :hidden-columns="hiddenColumns"
    :search-query="searchQuery"
    :active-filters="activeFilters"
    :active-filter-count="activeFilterCount"
    :has-selection="hasSelection"
    :selection-count="selectionCount"
    :can-edit="canEdit"
    :export-url="exportUrl"
    @update:search-query="searchQuery = $event"
    @set-filter="setFilter"
    @clear-filters="clearFilters"
    @toggle-column="toggleColumn"
    @reset-visibility="resetVisibility"
    @open-bulk-edit="openBulkEdit"
    @open-bulk-delete="openBulkDelete"
    @clear-selection="clearSelection"
  />

  <!-- Table card -->
  <div class="overflow-hidden rounded-lg border bg-card">
    <!-- Select all records banner -->
    <div
      v-if="
        allSelected &&
        isPaginated &&
        paginatorTotal > rows.length &&
        resource.bulkActions.length > 0
      "
      class="border-b border-primary/20 bg-primary/5 px-5 py-2.5 text-sm"
    >
      <template v-if="!isSelectAllRecords">
        {{
          t("builder.resources.page_selected", {
            count: rows.length,
          })
        }}
        <button
          class="ml-2 font-medium underline hover:no-underline"
          @click="selectAllRecords()"
        >
          {{
            t("builder.resources.select_all_records", {
              total: paginatorTotal,
            })
          }}
        </button>
      </template>
      <template v-else>
        {{
          t("builder.resources.all_records_selected", {
            total: paginatorTotal,
          })
        }}
        <button
          class="ml-2 font-medium underline hover:no-underline"
          @click="clearSelection()"
        >
          {{ t("builder.resources.clear_selection") }}
        </button>
      </template>
    </div>

    <ResourceTable
      :columns="visibleColumns"
      :rows="rows"
      :bulk-actions="resource.bulkActions"
      :selected-ids="selectedIds"
      :all-selected="allSelected"
      :sort-column="sortColumn"
      :sort-direction="sortDirection"
      :can-edit="canEdit"
      :has-custom-row-actions="resource.hasCustomRowActions"
      :is-hierarchical="resource.isHierarchical"
      :is-public="resource.isPublic"
      :public-url-base="resource.publicUrlBase"
      @toggle-sort="toggleSort"
      @toggle-all="toggleAll"
      @toggle-row="toggleRow"
      @edit-record="editRecord"
      @delete-record="deleteRecord"
    />

    <Pagination
      v-if="isPaginated"
      :links="paginatorLinks"
      :from="(records as Paginator).from"
      :to="(records as Paginator).to"
      :total="paginatorTotal"
      :per-page="perPage"
      @go-to-page="goToPage"
      @set-per-page="setPerPage"
    />
  </div>
</template>
