// Bookshelf functionality - procedural/imperative style

import { Alpine } from "./alpine";
import { showToast } from "./toast";
import { searchTagSuggestions, type TagSuggestion } from "./tag-dropdown";

function clearFilters(): void {
  // Clear all form state (reuses helper)
  clearFormWithoutSubmit();

  // Trigger form submit with cleared filters
  const filterForm = document.getElementById("filter-form") as HTMLFormElement;
  if (!filterForm) return;
  window.htmx.trigger(filterForm, "submit");
}

// Remove dynamically created hidden inputs from filter form
// Preserves: limit, offset, has_cover (static/managed inputs)
function cleanupDynamicHiddenInputs(): void {
  const filterForm = document.getElementById("filter-form") as HTMLFormElement;
  if (!filterForm) return;

  // Names of inputs to preserve (static or Alpine-managed)
  const preserveNames = ["limit", "offset", "has_cover"];

  // Find all hidden inputs
  const hiddenInputs = filterForm.querySelectorAll('input[type="hidden"]');
  hiddenInputs.forEach((input) => {
    const name = (input as HTMLInputElement).name;
    // Remove if it's not in our preserve list and has a name
    if (name && !preserveNames.includes(name)) {
      input.remove();
    }
  });
}

// Clear form fields WITHOUT submitting
// Used by loadFilter to reset state before applying new filter
function clearFormWithoutSubmit(): void {
  const filterForm = document.getElementById("filter-form") as HTMLFormElement;
  if (!filterForm) return;

  // Reset all form fields to their HTML defaults
  filterForm.reset();

  // Remove has_cover input entirely
  const hasCoverInput = document.querySelector(
    '[name="has_cover"]',
  ) as HTMLInputElement;
  if (hasCoverInput) {
    hasCoverInput.remove();
  }

  // Reset Alpine hasCoverState to null
  const bookshelfComponent = document.querySelector('[x-data*="bookshelf"]');
  if (bookshelfComponent && (bookshelfComponent as any)._x_dataStack) {
    const data = (bookshelfComponent as any)._x_dataStack[0];
    if (data && typeof data.hasCoverState !== "undefined") {
      data.hasCoverState = null;
    }
  }

  // Remove any hidden inputs from previous filter loads
  cleanupDynamicHiddenInputs();

  // Reset pagination to defaults
  const limitInput = filterForm.querySelector(
    'input[name="limit"]',
  ) as HTMLInputElement;
  const offsetInput = filterForm.querySelector(
    'input[name="offset"]',
  ) as HTMLInputElement;
  if (limitInput) limitInput.value = "50";
  if (offsetInput) offsetInput.value = "0";

  // NOTE: No form submit here!
}
// Alpine.js component
Alpine.data("bookshelf", () => ({
  // Component state
  showSaveModal: false,
  showFiltersDropdown: false,
  filtersOpen: false,
  hasCoverState: null as boolean | null,
  dropdownAlign: "right" as "left" | "right",
  resizeTimeout: null as number | null,
  tagSuggestions: [] as TagSuggestion[],
  showTagDropdown: false,
  tagHighlightIndex: -1,

  // Standalone function references (don't access component state)
  clearFilters,
  initBookshelf,

  // Inline method - opens the modal
  showSaveFilterModal() {
    this.showSaveModal = true;
  },
  // Helper method to calculate alignment
  calculateAlignment() {
    const button = document.querySelector("[data-load-filter-btn]");
    if (!button) return;

    const rect = button.getBoundingClientRect();
    const viewportWidth = window.innerWidth;
    const dropdownWidth = 320;

    const spaceOnLeft = rect.left;
    const spaceOnRight = viewportWidth - rect.right;

    if (spaceOnRight >= dropdownWidth) {
      this.dropdownAlign = "left";
    } else if (spaceOnLeft >= dropdownWidth) {
      this.dropdownAlign = "right";
    } else {
      this.dropdownAlign = spaceOnLeft > spaceOnRight ? "right" : "left";
    }
  },

  toggleFiltersDropdown() {
    this.showFiltersDropdown = !this.showFiltersDropdown;

    if (this.showFiltersDropdown) {
      this.$nextTick(() => {
        this.calculateAlignment();
      });
    }
  },
  // Alpine lifecycle hook - runs when component initializes
  init() {
    let rafId: number | null = null;

    window.addEventListener("resize", () => {
      if (rafId !== null) {
        cancelAnimationFrame(rafId);
      }

      rafId = requestAnimationFrame(() => {
        if (this.showFiltersDropdown) {
          this.calculateAlignment();
        }
        rafId = null;
      });
    });
  },
  // Cycle through has_cover states: null -> true -> false -> null
  cycleHasCover(): void {
    if (this.hasCoverState === null) {
      this.hasCoverState = true;
    } else if (this.hasCoverState === true) {
      this.hasCoverState = false;
    } else {
      this.hasCoverState = null;
    }
    // NOTE: We don't trigger form submission here
    // The user must click "Search" or press Enter to apply the filter
  },
  // Handle post-HTMX swap cleanup for saved filters
  afterFilterSave(): void {
    // Hide empty state if it exists
    const filtersList = document.getElementById("saved-filters-list");
    if (filtersList) {
      const emptyState = filtersList.nextElementSibling;
      if (emptyState && emptyState.textContent?.includes("No saved filters")) {
        emptyState.classList.add("hidden");
      }
    }
    // Close modal
    this.showSaveModal = false;
    // Show success toast
    showToast("Filter saved successfully", "success");
  },
  // Load a saved filter into the form
  async loadFilter(event: Event) {
    const button = event.target as HTMLElement;
    const filterRow = button.closest("[data-filter-id]");
    if (!filterRow) return;

    const filterId = filterRow?.getAttribute("data-filter-id");
    if (!filterId) return;

    const filterName = button.textContent?.trim() || "";

    showToast(`Loading filter: ${filterName}...`, "info");

    const token = localStorage.getItem("token");
    if (!token) {
      showToast("Not authenticated", "error");
      return;
    }

    try {
      // Fetch filter details from API
      const response = await fetch(`/api/saved-filters/${filterId}`, {
        headers: { Authorization: `Bearer ${token}` },
      });

      if (!response.ok) {
        if (response.status === 404) {
          showToast("Filter not found", "error");
        } else {
          showToast("Failed to load filter", "error");
        }
        return;
      }

      const filter = await response.json();

      // Parse filters JSON (string → object)
      const filterData: Record<string, string> =
        typeof filter.filters === "string"
          ? JSON.parse(filter.filters)
          : filter.filters;

      // Get the hidden filter form
      const filterForm = document.getElementById(
        "filter-form",
      ) as HTMLFormElement;
      if (!filterForm) {
        showToast("Filter form not found", "error");
        return;
      }

      // Clean up any hidden inputs from previous filter loads
      cleanupDynamicHiddenInputs();

      // Clear all form state before applying new filter
      clearFormWithoutSubmit();

      // Don't clear form - just update values
      // Populate form fields from filter data
      Object.entries(filterData).forEach(([key, value]) => {
        if (key === "has_cover") {
          const bookshelfComponent = document.querySelector(
            '[x-data*="bookshelf"]',
          );
          if (bookshelfComponent && (bookshelfComponent as any)._x_dataStack) {
            const data = (bookshelfComponent as any)._x_dataStack[0];
            if (data && typeof data.hasCoverState !== "undefined") {
              // Convert string value to boolean|null
              if (value === "true") {
                data.hasCoverState = true;
              } else if (value === "false") {
                data.hasCoverState = false;
              } else {
                data.hasCoverState = null;
              }
            }
          }
          return; // Don't process has_cover like other fields
        }

        if (!value) return; // Skip empty values
        // Special handling for has_cover - update Alpine state directly

        // Handle all other fields normally
        const visibleField = filterForm.querySelector(
          `[name="${key}"]`,
        ) as HTMLInputElement;
        if (visibleField) {
          if (visibleField.type === "checkbox") {
            visibleField.checked = value === "true";
          } else {
            visibleField.value = value;
          }
        } else {
          // Create hidden input if visible field doesn't exist
          const input = document.createElement("input");
          input.type = "hidden";
          input.name = key;
          input.value = value;
          filterForm.appendChild(input);
        }
      });

      // Trigger HTMX to apply the filter by submitting the form
      window.htmx.trigger(filterForm, "submit");

      showToast(`Filter applied: ${filterName}`, "success");

      // Close the dropdown after applying
      this.showFiltersDropdown = false;
    } catch (error) {
      console.error("Failed to load filter:", error);
      showToast("Error loading filter", "error");
    }
  },
  // Delete a saved filter
  async deleteFilter(event: Event) {
    const button = event.target as HTMLElement;
    const filterRow = button.closest("[data-filter-id]");
    if (!filterRow) return;

    const filterId = filterRow?.getAttribute("data-filter-id");
    if (!filterId) return;

    if (!confirm("Are you sure you want to delete this filter?")) return;

    const token = localStorage.getItem("token");
    if (!token) {
      showToast("Not authenticated", "error");
      return;
    }

    try {
      const response = await fetch(`/api/saved-filters/${filterId}`, {
        method: "DELETE",
        headers: { Authorization: `Bearer ${token}` },
      });

      if (response.ok) {
        showToast("Filter deleted", "success");
        // Remove the element from DOM
        filterRow?.remove();
      } else {
        showToast("Failed to delete filter", "error");
      }
    } catch (error) {
      console.error("Failed to delete filter:", error);
      showToast("Error deleting filter", "error");
    }
  },

  // Autocomplete helper function
  async fetchFieldValues(
    field: string,
    search: string,
    datalistId: string,
  ): Promise<void> {
    const token = localStorage.getItem("token");
    if (!token) {
      console.error("Not authenticated");
      return;
    }

    if (search.length < 2) return;

    const currentLibraryId = (
      document.getElementById("library-select") as HTMLSelectElement
    )?.value;

    const libParam = currentLibraryId ? `&library_id=${currentLibraryId}` : "";

    try {
      const response = await fetch(
        `/api/media-items/search?${field}=${encodeURIComponent(
          search,
        )}${libParam}&limit=50`,
        {
          headers: { Authorization: `Bearer ${token}` },
        },
      );

      if (!response.ok) {
        console.error("Failed to fetch field values");
        return;
      }

      const data = await response.json();

      // Update datalist via DOM manipulation
      const datalist = document.getElementById(datalistId);
      if (!datalist) {
        console.error(`Datalist ${datalistId} not found`);
        return;
      }

      // Clear existing options
      datalist.innerHTML = "";

      // Add new options
      data.results.forEach((item: { value: string; count: number }) => {
        const option = document.createElement("option");
        option.value = item.value;
        option.textContent = `${item.value} (${item.count})`;
        datalist.appendChild(option);
      });
    } catch (error) {
      console.error("Error fetching field values:", error);
    }
  },

  // Fetch author values for autocomplete
  async fetchAuthorValues(input: HTMLInputElement): Promise<void> {
    await this.fetchFieldValues("author", input.value, "author-datalist");
  },

  // Fetch tag values for autocomplete (custom dropdown)
  async fetchTagValues(input: HTMLInputElement): Promise<void> {
    const libraryId = (document.getElementById("library-select") as HTMLSelectElement)?.value;
    if (!libraryId || input.value.length < 2) {
      this.tagSuggestions = [];
      this.showTagDropdown = false;
      return;
    }
    const results = await searchTagSuggestions(input.value, libraryId);
    this.tagSuggestions = results;
    this.showTagDropdown = results.length > 0;
    this.tagHighlightIndex = -1;
  },

  selectTagSuggestion(tag: string) {
    const input = document.querySelector('input[name="tags_filter"]') as HTMLInputElement;
    if (input) input.value = tag;
    this.showTagDropdown = false;
    this.tagSuggestions = [];
    this.tagHighlightIndex = -1;
  },

  hideTagDropdown() {
    setTimeout(() => { this.showTagDropdown = false; this.tagHighlightIndex = -1; }, 200);
  },

  onTagFilterKeydown(event: KeyboardEvent) {
    if (event.key === "ArrowDown") {
      event.preventDefault();
      if (this.showTagDropdown && this.tagSuggestions.length > 0) {
        this.tagHighlightIndex = (this.tagHighlightIndex + 1) % this.tagSuggestions.length;
      }
    } else if (event.key === "ArrowUp") {
      event.preventDefault();
      if (this.showTagDropdown && this.tagSuggestions.length > 0) {
        this.tagHighlightIndex = this.tagHighlightIndex <= 0
          ? this.tagSuggestions.length - 1
          : this.tagHighlightIndex - 1;
      }
    } else if (event.key === "Enter" && this.tagHighlightIndex >= 0 && this.showTagDropdown) {
      event.preventDefault();
      this.selectTagSuggestion(this.tagSuggestions[this.tagHighlightIndex].value);
    } else if (event.key === "Escape") {
      this.showTagDropdown = false;
      this.tagSuggestions = [];
      this.tagHighlightIndex = -1;
    }
  },

  // // Fetch genre values for autocomplete
  // async fetchGenreValues(input: HTMLInputElement): Promise<void> {
  //   await this.fetchFieldValues("genre", input.value, "genre-datalist");
  // },

  // Fetch series values for autocomplete
  async fetchSeriesValues(input: HTMLInputElement): Promise<void> {
    await this.fetchFieldValues("series", input.value, "series-datalist");
  },

  // Fetch language values for autocomplete
  async fetchLanguageValues(input: HTMLInputElement): Promise<void> {
    await this.fetchFieldValues("language", input.value, "language-datalist");
  },
}));

// Standalone function - initialize the bookshelf (NOT async, like dashboard.ts)
function initBookshelf(): void {
  // Check if books were already rendered server-side
  const booksGrid = document.getElementById("books-grid");
  const hasServerBooks =
    booksGrid && booksGrid.querySelector("[data-book-id]") !== null;

  if (!hasServerBooks) {
    // Only trigger HTMX if no SSR books rendered
    const librarySelect = document.getElementById(
      "library-select",
    ) as HTMLSelectElement;
    librarySelect?.addEventListener("change", () => {
      localStorage.setItem("selectedLibrary", librarySelect.value);
    });
    if (librarySelect && librarySelect.value) {
      const filterForm = document.getElementById(
        "filter-form",
      ) as HTMLFormElement;
      if (filterForm) {
        // Trigger initial HTMX load
        window.htmx.trigger(librarySelect, "change");
      }
    }
  }
  // Setup listener for HTMX swap events on the filters list
  const filtersList = document.getElementById("saved-filters-list");
  if (filtersList) {
    filtersList.addEventListener("htmx:afterSwap", () => {
      const bookshelfElem = document.querySelector("[x-data*='bookshelf']");
      if (!bookshelfElem) return;
      const bookshelf = (bookshelfElem as any)._x_dataStack?.[0];
      if (!bookshelf) return;

      bookshelf.afterFilterSave();
    });
  }
}

export { clearFilters, cleanupDynamicHiddenInputs, clearFormWithoutSubmit };
