<!-- [DEF:DatasetHub:Page] -->
<script>
  /**
   * @TIER: CRITICAL
   * @PURPOSE: Dataset Hub - Dedicated hub for datasets with mapping progress
   * @LAYER: UI
   * @RELATION: BINDS_TO -> sidebarStore, taskDrawerStore
   * @INVARIANT: Always shows datasets for the active environment from context store
   *
   * @UX_STATE: Loading -> Shows skeleton loader
   * @UX_STATE: Loaded -> Shows dataset grid with mapping progress
   * @UX_STATE: Error -> Shows error banner with retry button
   * @UX_STATE: Selecting -> Checkboxes checked, floating action panel appears
   * @UX_STATE: BulkAction-Modal -> Map Columns or Generate Docs modal open
   * @UX_FEEDBACK: Clicking task status opens Task Drawer
   * @UX_FEEDBACK: Mapped % column shows progress bar + percentage text
   * @UX_FEEDBACK: Floating panel slides up from bottom when items selected
   * @UX_RECOVERY: Refresh button reloads dataset list
   *
   * @TEST_CONTRACT Page_DatasetHub ->
   * {
   *   required_props: {},
   *   optional_props: {},
   *   invariants: [
   *       "Loads datasets on mount leveraging the environment store context",
   *       "Updates dataset selection state correctly",
   *       "Renders the bulk actions panel when one or more datasets are selected",
   *       "Shows map columns configuration modal appropriately"
   *   ]
   * }
   * @TEST_FIXTURE init_state -> {}
   * @TEST_EDGE server_error -> shows error block and retry button
   * @TEST_EDGE multi_selection -> sets `isAllSelected`/`isAllVisibleSelected` properly and shows bottom panel
   * @TEST_INVARIANT dataset_grid_and_selection -> verifies: [init_state]
   */

  import { onMount } from "svelte";
  import { goto } from "$app/navigation";
  import { fromStore } from "svelte/store";
  import { t } from "$lib/i18n";
  import {
    openDrawerForTask,
    openDrawerForTaskIfPreferred,
  } from "$lib/stores/taskDrawer.js";
  import { api } from "$lib/api.js";
  import { debounce } from "$lib/utils/debounce.js";
  import {
    environmentContextStore,
    initializeEnvironmentContext,
    setSelectedEnvironment,
    selectedEnvironmentStore,
  } from "$lib/stores/environmentContext.js";

  const environmentContextState = fromStore(environmentContextStore);
  const selectedEnvironmentState = fromStore(selectedEnvironmentStore);

  // State
  let selectedEnv = $state(null);
  let datasets = $state([]);
  let isLoading = $state(true);
  let error = $state(null);

  // Pagination state
  let currentPage = $state(1);
  let pageSize = $state(10);
  let totalPages = $state(1);
  let total = $state(0);

  // Selection state
  let selectedIds = $state(new Set());
  let isAllSelected = $state(false);
  let isAllVisibleSelected = $state(false);

  // Search state
  let searchQuery = $state("");

  // Bulk action modal state
  let showMapColumnsModal = $state(false);
  let showGenerateDocsModal = $state(false);
  let mapSourceType = $state("postgresql");
  let mapConnectionId = $state("");
  let mapFileData = $state(null);
  let mapFileInput = $state(null);
  let llmProvider = $state("");
  let llmOptions = $state({});

  // Environment options - will be loaded from API
  let environments = $derived(
    environmentContextState.current?.environments || [],
  );
  let activeEnvironment = $derived(selectedEnvironmentState.current || null);

  // Debounced search function
  const debouncedSearch = debounce((query) => {
    searchQuery = query;
    loadDatasets();
  }, 300);

  // Load environments and datasets on mount
  onMount(async () => {
    await initializeEnvironmentContext();
    if (!selectedEnv && environmentContextState.current?.selectedEnvId) {
      selectedEnv = environmentContextState.current.selectedEnvId;
    }
    await loadDatasets();
  });

  // Load datasets from API
  async function loadDatasets() {
    if (!selectedEnv) return;

    isLoading = true;
    error = null;
    try {
      const response = await api.getDatasets(selectedEnv, {
        search: searchQuery || undefined,
        page: currentPage,
        page_size: pageSize,
      });

      // Preserve selected IDs across pagination
      const newSelectedIds = new Set();
      response.datasets.forEach((d) => {
        if (selectedIds.has(d.id)) {
          newSelectedIds.add(d.id);
        }
      });
      selectedIds = newSelectedIds;

      datasets = response.datasets.map((d) => ({
        id: d.id,
        table_name: d.table_name,
        schema: d.schema,
        database: d.database,
        mappedFields: d.mapped_fields
          ? {
              total: d.mapped_fields.total,
              mapped: d.mapped_fields.mapped,
            }
          : null,
        lastTask: d.last_task
          ? {
              status: d.last_task.status?.toLowerCase() || null,
              id: d.last_task.task_id,
            }
          : null,
        actions: ["map_columns"], // All datasets have map columns option
      }));

      // Update pagination state
      total = response.total;
      totalPages = response.total_pages;

      // Update selection state
      updateSelectionState();
    } catch (err) {
      error = err.message || $t.datasets?.load_failed;
      console.error("[DatasetHub][Coherence:Failed]", err);
    } finally {
      isLoading = false;
    }
  }

  // Handle search input
  function handleSearch(event) {
    debouncedSearch(event.target.value);
  }

  // Handle page change
  function handlePageChange(page) {
    currentPage = page;
    loadDatasets();
  }

  // Handle page size change
  function handlePageSizeChange(event) {
    pageSize = parseInt(event.target.value);
    currentPage = 1;
    loadDatasets();
  }

  // Update selection state based on current selection
  function updateSelectionState() {
    const visibleCount = datasets.length;
    const totalCount = total;

    isAllSelected = selectedIds.size === totalCount && totalCount > 0;
    isAllVisibleSelected =
      selectedIds.size === visibleCount && visibleCount > 0;
  }

  // Handle checkbox change for individual dataset
  function handleCheckboxChange(dataset, event) {
    if (event.target.checked) {
      selectedIds.add(dataset.id);
    } else {
      selectedIds.delete(dataset.id);
    }
    selectedIds = selectedIds; // Trigger reactivity
    updateSelectionState();
  }

  // Handle select all
  async function handleSelectAll() {
    if (isAllSelected) {
      selectedIds.clear();
    } else {
      // Get all dataset IDs from API (including non-visible ones)
      try {
        const response = await api.getDatasetIds(selectedEnv, {
          search: searchQuery || undefined,
        });
        response.dataset_ids.forEach((id) => selectedIds.add(id));
      } catch (err) {
        console.error(
          "[DatasetHub][Coherence:Failed] Failed to fetch all dataset IDs:",
          err,
        );
        // Fallback to selecting visible datasets if API fails
        datasets.forEach((d) => selectedIds.add(d.id));
      }
    }
    selectedIds = selectedIds; // Trigger reactivity
    updateSelectionState();
  }

  // Handle select visible
  function handleSelectVisible() {
    if (isAllVisibleSelected) {
      datasets.forEach((d) => selectedIds.delete(d.id));
    } else {
      datasets.forEach((d) => selectedIds.add(d.id));
    }
    selectedIds = selectedIds; // Trigger reactivity
    updateSelectionState();
  }

  // Handle action click
  function handleAction(dataset, action) {
    console.log(
      `[DatasetHub][Action] ${action} on dataset ${dataset.table_name}`,
    );

    if (action === "map_columns") {
      // Show map columns modal
      showMapColumnsModal = true;
      mapSourceType = "postgresql";
      mapConnectionId = null;
      mapFileData = null;
    } else if (action === "generate_docs") {
      // Show generate docs modal
      showGenerateDocsModal = true;
      llmProvider = "";
      llmOptions = {};
    }
  }

  // Handle bulk map columns
  async function handleBulkMapColumns() {
    console.log("[DatasetHub][handleBulkMapColumns][Entry]", {
      selectedIds: Array.from(selectedIds),
      mapSourceType,
      mapConnectionId,
      mapFileData,
    });

    if (selectedIds.size === 0) {
      console.log("[DatasetHub][handleBulkMapColumns] No datasets selected");
      return;
    }

    if (mapSourceType === "postgresql" && !mapConnectionId) {
      console.log(
        "[DatasetHub][handleBulkMapColumns] No connection ID provided for PostgreSQL",
      );
      return;
    }

    if (
      mapSourceType === "xlsx" &&
      (!mapFileData || mapFileData.length === 0)
    ) {
      console.log(
        "[DatasetHub][handleBulkMapColumns] No file selected for XLSX",
      );
      return;
    }

    try {
      let fileData = null;
      if (mapSourceType === "xlsx" && mapFileData && mapFileData.length > 0) {
        // For now we send the filename as a placeholder or handle upload if needed.
        // The backend expects a string 'file_data' in the current schema.
        fileData = mapFileData[0].name;
      }

      const response = await api.postApi("/datasets/map-columns", {
        env_id: selectedEnv,
        dataset_ids: Array.from(selectedIds),
        source_type: mapSourceType,
        connection_id: mapConnectionId || undefined,
        file_data: fileData || undefined,
      });
      console.log(
        "[DatasetHub][Action] Bulk map columns task created:",
        response.task_id,
      );

      // Close modal and open task drawer
      showMapColumnsModal = false;
      selectedIds.clear();
      updateSelectionState();

      if (response.task_id) {
        openDrawerForTaskIfPreferred(response.task_id);
      }
    } catch (err) {
      console.error("[DatasetHub][Coherence:Failed]", err);
      alert($t.datasets?.mapping_task_failed);
    }
  }

  // Handle bulk generate docs
  async function handleBulkGenerateDocs() {
    if (selectedIds.size === 0) return;
    if (!llmProvider) {
      alert($t.datasets?.select_llm_provider);
      return;
    }

    try {
      const response = await api.postApi("/datasets/generate-docs", {
        env_id: selectedEnv,
        dataset_ids: Array.from(selectedIds),
        llm_provider: llmProvider,
        options: llmOptions,
      });
      console.log(
        "[DatasetHub][Action] Bulk generate docs task created:",
        response.task_id,
      );

      // Close modal and open task drawer
      showGenerateDocsModal = false;
      selectedIds.clear();
      updateSelectionState();

      if (response.task_id) {
        openDrawerForTaskIfPreferred(response.task_id);
      }
    } catch (err) {
      console.error("[DatasetHub][Coherence:Failed]", err);
      alert($t.datasets?.docs_task_failed);
    }
  }

  // Handle task status click - open Task Drawer
  function handleTaskStatusClick(dataset) {
    if (dataset.lastTask?.id) {
      console.log(
        `[DatasetHub][Action] Open task drawer for task ${dataset.lastTask.id}`,
      );
      openDrawerForTask(dataset.lastTask.id);
    }
  }

  // Get task status icon
  function getTaskStatusIcon(status) {
    if (!status) return "";
    switch (status.toLowerCase()) {
      case "running":
        return '<svg class="animate-spin" width="16" height="16" viewBox="0 0 24 24"><path fill="currentColor" d="M12 2a10 10 0 1 0 10 10A10 10 0 0 0 12 2zm0 18a8 8 0 1 1 8-8 8 0 0 1-8 8z"/></svg>';
      case "success":
        return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41L9 16.17z"/></svg>';
      case "error":
        return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>';
      case "waiting_input":
        return '<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/></svg>';
      default:
        return "";
    }
  }

  // Get mapping progress bar class
  function getMappingProgressClass(mapped, total) {
    if (!mapped || !total) return "bg-gray-200";
    const percentage = (mapped / total) * 100;
    if (percentage === 100) {
      return "bg-green-500";
    } else if (percentage >= 50) {
      return "bg-yellow-400";
    } else {
      return "bg-blue-400";
    }
  }

  $effect(() => {
    const nextSelectedEnvId = environmentContextState.current?.selectedEnvId;
    if (!nextSelectedEnvId || selectedEnv === nextSelectedEnvId) return;
    selectedEnv = nextSelectedEnvId;
    setSelectedEnvironment(selectedEnv);
    currentPage = 1;
    selectedIds.clear();
    void loadDatasets();
  });
</script>

<div class="max-w-[80rem] mx-auto px-4 pt-6 pb-6">
  <!-- Header -->
  <div class="flex items-center justify-between mb-6">
    <h1 class="text-2xl font-bold text-gray-900">{$t.nav?.datasets}</h1>
    <div class="flex items-center gap-4">
      <span
        class="px-3 py-1 text-sm rounded border border-gray-300 bg-gray-50 text-gray-700"
      >
        {$t.dashboard?.environment}: {activeEnvironment?.name ||
          selectedEnv ||
          "-"}
      </span>
      <button
        class="px-2 py-1 bg-blue-600 text-white rounded hover:bg-blue-700"
        onclick={loadDatasets}
      >
        {$t.common?.refresh}
      </button>
    </div>
  </div>

  <!-- Error Banner -->
  {#if error}
    <div
      class="bg-red-100 border border-red-400 text-red-700 px-3 py-2 rounded mb-4 flex items-center justify-between"
    >
      <span>{error}</span>
      <button
        class="px-2 py-1 bg-red-600 text-white rounded hover:bg-red-700"
        onclick={loadDatasets}
      >
        {$t.common?.retry}
      </button>
    </div>
  {/if}

  <!-- Loading State -->
  {#if isLoading}
    <div class="bg-white border border-gray-200 rounded overflow-hidden">
      <div
        class="grid grid-cols-12 gap-4 px-6 py-3 bg-gray-50 border-b border-gray-200 text-sm font-semibold text-gray-500"
      >
        <div class="col-span-1 animate-pulse bg-gray-200 rounded h-4"></div>
        <div class="col-span-3 animate-pulse bg-gray-200 rounded h-4"></div>
        <div class="col-span-2 animate-pulse bg-gray-200 rounded h-4"></div>
        <div class="col-span-2 animate-pulse bg-gray-200 rounded h-4"></div>
        <div class="col-span-3 animate-pulse bg-gray-200 rounded h-4"></div>
        <div class="col-span-1 animate-pulse bg-gray-200 rounded h-4"></div>
      </div>
      {#each Array(5) as _}
        <div class="grid grid-cols-12 gap-4 px-6 py-4 border-b border-gray-200">
          <div class="col-span-1 animate-pulse bg-gray-200 rounded h-4"></div>
          <div class="col-span-3 animate-pulse bg-gray-200 rounded h-4"></div>
          <div class="col-span-2 animate-pulse bg-gray-200 rounded h-4"></div>
          <div class="col-span-2 animate-pulse bg-gray-200 rounded h-4"></div>
          <div class="col-span-3 animate-pulse bg-gray-200 rounded h-4"></div>
          <div class="col-span-1 animate-pulse bg-gray-200 rounded h-4"></div>
        </div>
      {/each}
    </div>
  {:else if datasets.length === 0}
    <!-- Empty State -->
    <div class="py-12 text-center text-gray-500">
      <svg
        class="w-16 h-16 mx-auto mb-4 text-gray-400"
        xmlns="http://www.w3.org/2000/svg"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        stroke-width="2"
      >
        <path d="M3 3h18v18H3V3zm16 16V5H5v14h14z" />
      </svg>
      <p>{$t.datasets?.empty}</p>
    </div>
  {:else}
    <!-- Toolbar -->
    <div class="flex items-center justify-between mb-4 gap-4">
      <div class="flex items-center gap-2">
        <button
          class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100"
          onclick={handleSelectAll}
          disabled={total === 0}
        >
          {isAllSelected ? $t.datasets?.deselect_all : $t.datasets?.select_all}
        </button>
        <button
          class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100"
          onclick={handleSelectVisible}
          disabled={datasets.length === 0}
        >
          {isAllVisibleSelected
            ? $t.datasets?.deselect_visible
            : $t.datasets?.select_visible}
        </button>
        {#if selectedIds.size > 0}
          <span class="text-sm text-gray-600">
            {$t.datasets?.selected_count?.replace(
              "{count}",
              String(selectedIds.size),
            )}
          </span>
        {/if}
      </div>
      <div>
        <input
          type="text"
          class="px-2 py-1 border border-gray-300 rounded bg-white focus:outline-none focus:ring-2 focus:ring-blue-500"
          placeholder={$t.datasets?.search_placeholder}
          oninput={handleSearch}
          value={searchQuery}
        />
      </div>
    </div>

    <!-- Dataset Grid -->
    <div class="bg-white border border-gray-200 rounded overflow-hidden">
      <!-- Grid Header -->
      <div
        class="grid grid-cols-12 gap-4 px-6 py-3 bg-gray-50 border-b border-gray-200 text-sm font-semibold text-gray-500"
      >
        <div class="col-span-1"></div>
        <div class="col-span-3 font-medium text-gray-700">
          {$t.datasets?.table_name}
        </div>
        <div class="col-span-2">{$t.datasets?.schema}</div>
        <div class="col-span-2">{$t.datasets?.mapped_fields}</div>
        <div class="col-span-3">{$t.datasets?.last_task}</div>
        <div class="col-span-1">{$t.datasets?.actions}</div>
      </div>

      <!-- Grid Rows -->
      {#each datasets as dataset}
        <div
          class="grid grid-cols-12 gap-4 px-6 py-4 border-b border-gray-200 hover:bg-gray-50 last:border-b-0"
        >
          <!-- Checkbox -->
          <div class="col-span-1">
            <input
              type="checkbox"
              checked={selectedIds.has(dataset.id)}
              onchange={(e) => handleCheckboxChange(dataset, e)}
            />
          </div>

          <!-- Table Name -->
          <div class="col-span-3 font-medium text-gray-900">
            <a
              href={`/datasets/${dataset.id}?env_id=${selectedEnv}`}
              class="text-blue-600 hover:text-blue-800 hover:underline"
            >
              {dataset.table_name}
            </a>
          </div>

          <!-- Schema -->
          <div class="col-span-2">
            {dataset.schema}
          </div>

          <!-- Mapping Progress -->
          <div class="col-span-2">
            {#if dataset.mappedFields}
              <div
                class="w-24 h-2 rounded-full overflow-hidden"
                title="{$t.datasets?.mapped_of_total}: {dataset.mappedFields
                  .mapped} / {dataset.mappedFields.total}"
              >
                <div
                  class="h-full transition-all {getMappingProgressClass(
                    dataset.mappedFields.mapped,
                    dataset.mappedFields.total,
                  )}"
                  style="width: {(dataset.mappedFields.mapped /
                    dataset.mappedFields.total) *
                    100}%"
                ></div>
              </div>
            {:else}
              <span class="text-gray-400">-</span>
            {/if}
          </div>

          <!-- Last Task -->
          <div class="col-span-3">
            {#if dataset.lastTask}
              <button
                type="button"
                class="inline-flex items-center gap-2 hover:text-blue-600"
                onclick={() => handleTaskStatusClick(dataset)}
                aria-label={$t.datasets?.view_task}
              >
                {@html getTaskStatusIcon(dataset.lastTask.status)}
                <span>
                  {#if dataset.lastTask.status.toLowerCase() === "running"}
                    {$t.datasets?.task_running}
                  {:else if dataset.lastTask.status.toLowerCase() === "success"}
                    {$t.datasets?.task_done}
                  {:else if dataset.lastTask.status.toLowerCase() === "error"}
                    {$t.datasets?.task_failed}
                  {:else if dataset.lastTask.status.toLowerCase() === "waiting_input"}
                    {$t.datasets?.task_waiting}
                  {/if}
                </span>
              </button>
            {:else}
              <span class="text-gray-400">-</span>
            {/if}
          </div>

          <!-- Actions -->
          <div class="col-span-1">
            {#if dataset.actions.includes("map_columns")}
              <button
                class="px-1 py-0.5 text-sm bg-blue-600 text-white rounded hover:bg-blue-700"
                onclick={() => handleAction(dataset, "map_columns")}
                aria-label={$t.datasets?.action_map_columns}
              >
                {$t.datasets?.action_map_columns}
              </button>
            {/if}
          </div>
        </div>
      {/each}
    </div>

    <!-- Pagination -->
    {#if totalPages > 1}
      <div
        class="flex items-center justify-between px-3 py-3 bg-gray-50 border-t border-gray-200"
      >
        <div class="text-sm text-gray-500">
          {$t.datasets?.showing
            .replace("{start}", String((currentPage - 1) * pageSize + 1))
            .replace("{end}", String(Math.min(currentPage * pageSize, total)))
            .replace("{total}", String(total))}
        </div>
        <div class="flex items-center gap-2">
          <button
            class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
            onclick={() => handlePageChange(1)}
            disabled={currentPage === 1}
          >
            {$t.common?.first}
          </button>
          <button
            class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
            onclick={() => handlePageChange(currentPage - 1)}
            disabled={currentPage === 1}
          >
            {$t.dashboard?.previous}
          </button>
          {#each Array.from({ length: totalPages }, (_, i) => i + 1) as pageNum}
            <button
              class="px-2 py-1 text-sm border rounded {pageNum === currentPage
                ? 'bg-blue-600 text-white border-blue-600'
                : 'border-gray-300 hover:bg-gray-100'}"
              onclick={() => handlePageChange(pageNum)}
            >
              {pageNum}
            </button>
          {/each}
          <button
            class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
            onclick={() => handlePageChange(currentPage + 1)}
            disabled={currentPage === totalPages}
          >
            {$t.dashboard?.next}
          </button>
          <button
            class="px-2 py-1 text-sm border border-gray-300 rounded hover:bg-gray-100 disabled:opacity-50 disabled:cursor-not-allowed"
            onclick={() => handlePageChange(totalPages)}
            disabled={currentPage === totalPages}
          >
            {$t.common?.last}
          </button>
        </div>
        <div>
          <select
            class="px-2 py-1 border border-gray-300 rounded bg-white focus:outline-none focus:ring-2 focus:ring-blue-500"
            value={pageSize}
            onchange={handlePageSizeChange}
          >
            <option value={5}>5 {$t.common?.per_page}</option>
            <option value={10}>10 {$t.common?.per_page}</option>
            <option value={25}>25 {$t.common?.per_page}</option>
            <option value={50}>50 {$t.common?.per_page}</option>
            <option value={100}>100 {$t.common?.per_page}</option>
          </select>
        </div>
      </div>
    {/if}

    <!-- Floating Bulk Action Panel -->
    {#if selectedIds.size > 0}
      <div
        class="fixed bottom-0 left-0 right-0 bg-white border-t border-gray-200 shadow-lg p-4 translate-y-0"
      >
        <div class="flex items-center justify-between max-w-7xl mx-auto">
          <div class="flex items-center gap-4">
            <span class="font-medium">
              ✓ {selectedIds.size}
              {$t.datasets?.selected}
            </span>
          </div>
          <div class="flex gap-3">
            <button
              class="px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700"
              onclick={() => (showMapColumnsModal = true)}
            >
              {$t.datasets?.action_map_columns}
            </button>
            <button
              class="px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700"
              onclick={() => (showGenerateDocsModal = true)}
            >
              {$t.datasets?.generate_docs}
            </button>
            <button
              class="px-3 py-1.5 border border-gray-300 rounded hover:bg-gray-100"
              onclick={() => selectedIds.clear()}
            >
              {$t.common?.cancel}
            </button>
          </div>
        </div>
      </div>
    {/if}
  {/if}

  <!-- Map Columns Modal -->
  {#if showMapColumnsModal}
    <div
      class="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
      onclick={() => (showMapColumnsModal = false)}
      onkeydown={(event) => event.key === "Escape" && (showMapColumnsModal = false)}
      role="button"
      tabindex="0"
      aria-label={$t.common?.close_modal}
    >
      <div
        class="bg-white rounded-lg shadow-2xl max-w-xl w-full m-4 max-h-[80vh] overflow-y-auto"
      >
        <div
          class="px-4 py-3 border-b border-gray-200 flex items-center justify-between relative"
        >
          <h2 class="text-xl font-bold">{$t.datasets?.bulk_map_columns}</h2>
          <button
            onclick={() => (showMapColumnsModal = false)}
            class="absolute top-4 right-4 p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full"
            aria-label={$t.common?.close_modal}
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="20"
              height="20"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            >
              <line x1="18" y1="6" x2="6" y2="18"></line>
              <line x1="6" y1="6" x2="18" y2="18"></line>
            </svg>
          </button>
        </div>
        <div class="p-4">
          <div class="space-y-4">
            <div>
              <label class="block text-sm font-medium mb-2" for="map-source-type">
                {$t.datasets?.source_type}
              </label>
              <select
                id="map-source-type"
                class="w-full px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
                bind:value={mapSourceType}
              >
                <option value="postgresql"
                  >{$t.datasets?.source_postgresql_comments}</option
                >
                <option value="xlsx">{$t.datasets?.source_xlsx}</option>
              </select>
            </div>
            {#if mapSourceType === "postgresql"}
              <div>
                <label class="block text-sm font-medium mb-2" for="map-connection-id">
                  {$t.datasets?.connection_id}
                </label>
                <input
                  id="map-connection-id"
                  type="text"
                  class="w-full px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
                  placeholder={$t.datasets?.connection_id_placeholder}
                  bind:value={mapConnectionId}
                />
              </div>
            {:else}
              <div>
                <label class="block text-sm font-medium mb-2" for="map-file-input">
                  {$t.datasets?.xlsx_file}
                </label>
                <input
                  id="map-file-input"
                  type="file"
                  class="w-full"
                  accept=".xlsx,.xls"
                  bind:files={mapFileData}
                  bind:this={mapFileInput}
                />
              </div>
            {/if}
            <div>
              <p class="block text-sm font-medium mb-2">
                {$t.datasets?.selected_datasets}
              </p>
              <div class="max-h-40 overflow-y-auto" aria-label={$t.datasets?.selected_datasets}>
                {#each Array.from(selectedIds) as id}
                  {#each datasets as d}
                    {#if d.id === id}
                      <div class="text-sm py-1 border-b border-gray-200">
                        {d.table_name}
                      </div>
                    {/if}
                  {/each}
                {/each}
              </div>
            </div>
          </div>
        </div>
        <div class="px-4 py-3 border-t border-gray-200 flex justify-end gap-3">
          <button
            class="px-3 py-1.5 border border-gray-300 rounded hover:bg-gray-100"
            onclick={() => (showMapColumnsModal = false)}
            >{$t.common?.cancel}</button
          >
          <button
            type="button"
            class="px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
            onclick={(event) => {
              event.preventDefault();
              handleBulkMapColumns();
            }}
            disabled={selectedIds.size === 0 ||
              (mapSourceType === "postgresql" && !mapConnectionId) ||
              (mapSourceType === "xlsx" &&
                (!mapFileData || mapFileData.length === 0))}
          >
            {$t.datasets?.start_mapping}
          </button>
        </div>
      </div>
    </div>
  {/if}

  <!-- Generate Docs Modal -->
  {#if showGenerateDocsModal}
    <div
      class="fixed inset-0 bg-black/50 flex items-center justify-center z-50"
      onclick={() => (showGenerateDocsModal = false)}
      onkeydown={(event) => event.key === "Escape" && (showGenerateDocsModal = false)}
      role="button"
      tabindex="0"
      aria-label={$t.common?.close_modal}
    >
      <div
        class="bg-white rounded-lg shadow-2xl max-w-xl w-full m-4 max-h-[80vh] overflow-y-auto"
      >
        <div
          class="px-4 py-3 border-b border-gray-200 flex items-center justify-between relative"
        >
          <h2 class="text-xl font-bold">{$t.datasets?.bulk_docs_generation}</h2>
          <button
            onclick={() => (showGenerateDocsModal = false)}
            class="absolute top-4 right-4 p-1 text-gray-400 hover:text-gray-600 hover:bg-gray-100 rounded-full"
            aria-label={$t.common?.close_modal}
          >
            <svg
              xmlns="http://www.w3.org/2000/svg"
              width="20"
              height="20"
              viewBox="0 0 24 24"
              fill="none"
              stroke="currentColor"
              stroke-width="2"
              stroke-linecap="round"
              stroke-linejoin="round"
            >
              <line x1="18" y1="6" x2="6" y2="18"></line>
              <line x1="6" y1="6" x2="18" y2="18"></line>
            </svg>
          </button>
        </div>
        <div class="p-4">
          <div class="space-y-4">
            <div>
              <label class="block text-sm font-medium mb-2" for="llm-provider-select">
                {$t.dashboard?.llm_provider}
              </label>
              <select
                id="llm-provider-select"
                class="w-full px-2 py-1 border border-gray-300 rounded focus:outline-none focus:ring-2 focus:ring-blue-500"
                bind:value={llmProvider}
              >
                <option value=""
                  >{$t.datasets?.select_llm_provider_option}</option
                >
                <option value="openai">OpenAI</option>
                <option value="anthropic">Anthropic</option>
                <option value="cohere">Cohere</option>
              </select>
            </div>
            <div>
              <p class="block text-sm font-medium mb-2">
                {$t.datasets?.selected_datasets}
              </p>
              <div class="max-h-40 overflow-y-auto" aria-label={$t.datasets?.selected_datasets}>
                {#each Array.from(selectedIds) as id}
                  {#each datasets as d}
                    {#if d.id === id}
                      <div class="text-sm py-1 border-b border-gray-200">
                        {d.table_name}
                      </div>
                    {/if}
                  {/each}
                {/each}
              </div>
            </div>
          </div>
        </div>
        <div class="px-4 py-3 border-t border-gray-200 flex justify-end gap-3">
          <button
            class="px-3 py-1.5 border border-gray-300 rounded hover:bg-gray-100"
            onclick={() => (showGenerateDocsModal = false)}
            >{$t.common?.cancel}</button
          >
          <button
            class="px-3 py-1.5 bg-blue-600 text-white rounded hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed"
            onclick={handleBulkGenerateDocs}
            disabled={!llmProvider || selectedIds.size === 0}
          >
            {$t.datasets?.generate_documentation}
          </button>
        </div>
      </div>
    </div>
  {/if}
</div>

<!-- [/DEF:DatasetHub:Page] -->
