--- FFF.nvim File Picker - High-performance file picker for Neovim
--- Uses advanced fuzzy search algorithm with frecency scoring

local M = {}
local fuzzy = require('fff.core').ensure_initialized()

M.state = {
  initialized = false,
  base_path = nil,
  last_scan_time = 0,
}

function M.setup()
  local config = require('fff.conf').get()
  M.state.initialized = true
  M.state.base_path = config.base_path

  return true
end

--- Trigger scan of files in the current directory (asynchronous)
function M.scan_files()
  if not M.state.initialized then return end

  local ok, result = pcall(fuzzy.scan_files)
  if not ok then
    vim.notify('Failed to trigger file scan: ' .. tostring(result), vim.log.levels.ERROR)
    return
  end

  M.state.last_scan_time = os.time()
end

--- Search files with fuzzy matching using blink.cmp's advanced algorithm
--- Results are always returned in descending order (best scores first)
--- @param query string Search query
--- @param max_results number|nil Maximum number of results (optional)
--- @param max_threads number|nil Maximum number of threads (optional)
--- @param current_file string|nil Path to current file to deprioritize (optional)
--- @param min_combo_count_override number|nil Optional override for min_combo_count (nil uses config)
--- @return table List of matching files
function M.search_files(query, current_file, max_results, max_threads, min_combo_count_override)
  -- Delegate to paginated version with offset=0 and limit=max_results
  return M.search_files_paginated(query, current_file, max_threads, min_combo_count_override, 0, max_results)
end

--- Search files with pagination support
--- Results are always returned in descending order (best scores first)
--- @param query string Search query
--- @param current_file string|nil Path to current file to deprioritize (optional)
--- @param max_threads number|nil Maximum number of threads to use
--- @param min_combo_count_override number|nil Optional override for min_combo_count (nil uses config)
--- @param page_index number Page index (0-based: 0, 1, 2, ...)
--- @param page_size number|nil Items per page (nil uses config default)
--- @return table List of matching files
function M.search_files_paginated(query, current_file, max_threads, min_combo_count_override, page_index, page_size)
  local config = require('fff.conf').get()
  if not M.state.initialized then return {} end

  max_threads = max_threads or config.max_threads or 4
  page_index = page_index or 0
  page_size = page_size or 0

  local min_combo_count = min_combo_count_override
  if min_combo_count == nil then min_combo_count = config.history and config.history.min_combo_count or 3 end

  local combo_boost_score_multiplier = config.history and config.history.combo_boost_score_multiplier or 100

  -- Convert page_index to offset (Rust expects offset in items, not page number)
  local offset = page_index * page_size

  local ok, search_result = pcall(
    fuzzy.fuzzy_search_files,
    query,
    max_threads,
    current_file,
    combo_boost_score_multiplier,
    min_combo_count,
    offset,
    page_size
  )

  if not ok then
    vim.notify('Failed to search files: ' .. tostring(search_result), vim.log.levels.ERROR)
    return {}
  end

  M.state.last_search_result = search_result
  return search_result.items
end

--- Get the last search result metadata
--- @return table Search metadata with total_matched and total_files
function M.get_search_metadata()
  if not M.state.last_search_result then return { total_matched = 0, total_files = 0 } end
  return {
    total_matched = M.state.last_search_result.total_matched,
    total_files = M.state.last_search_result.total_files,
  }
end

--- Get location data from the last search result
--- @return table|nil Location data if available
function M.get_search_location()
  if not M.state.last_search_result then return nil end
  return M.state.last_search_result.location
end

--- Get score information for a file by index (1-based)
--- @param index number The index of the file in the last search results
--- @return table|nil Score information or nil if not available
function M.get_file_score(index)
  if not M.state.last_search_result or not M.state.last_search_result.scores then return nil end

  return M.state.last_search_result.scores[index]
end

--- Record file access for frecency tracking
--- @param file_path string Path to the file that was accessed
function M.track_access(file_path)
  if not M.state.initialized then return end

  local ok, result = pcall(fuzzy.track_access, file_path)
  if not ok then vim.notify('Failed to record file access: ' .. tostring(result), vim.log.levels.WARN) end
end

--- Get file content for preview
--- @param file_path string Path to the file
--- @return string|nil File content or nil if failed
function M.get_file_preview(file_path)
  local preview = require('fff.file_picker.preview')

  -- Create a temporary buffer to get the preview
  local temp_buf = vim.api.nvim_create_buf(false, true)
  local success = preview.preview(file_path, temp_buf)

  if not success then
    vim.api.nvim_buf_delete(temp_buf, { force = true })
    return nil
  end

  local lines = vim.api.nvim_buf_get_lines(temp_buf, 0, -1, false)
  vim.api.nvim_buf_delete(temp_buf, { force = true })

  return table.concat(lines, '\n')
end

--- Check if file picker is initialized
--- @return boolean
function M.is_initialized() return M.state.initialized end

--- Get scan progress information
--- @return table Progress information with scanned_files_count, is_scanning
function M.get_scan_progress()
  if not M.state.initialized then return { total_files = 0, scanned_files_count = 0, is_scanning = false } end

  local ok, result = pcall(fuzzy.get_scan_progress)
  if not ok then
    vim.notify('Failed to get scan progress: ' .. tostring(result), vim.log.levels.WARN)
    return { scanned_files_count = 0, is_scanning = false }
  end

  return result
end

--- Refresh git status on cached files (call after git status loading completes)
--- @return table List of files with updated git status
function M.refresh_git_status()
  if not M.state.initialized then return {} end

  local ok, result = pcall(fuzzy.refresh_git_status)
  if not ok then
    vim.notify('Failed to refresh git status: ' .. tostring(result), vim.log.levels.WARN)
    return {}
  end

  -- Update our cache
  return result
end

--- Stop background git status monitoring
--- @return boolean Success status
function M.stop_background_monitor()
  if not M.state.initialized then return false end

  local ok, result = pcall(fuzzy.stop_background_monitor)
  if not ok then
    vim.notify('Failed to stop background monitor: ' .. tostring(result), vim.log.levels.WARN)
    return false
  end
  return result
end

--- Wait for initial scan to complete
--- @param timeout_ms number Optional timeout in milliseconds (default 5000)
--- @return boolean True if scan completed, false if timed out
function M.wait_for_initial_scan(timeout_ms)
  if not M.state.initialized then return false end

  local ok, result = pcall(fuzzy.wait_for_initial_scan, timeout_ms)
  if not ok then
    vim.notify('Failed to wait for initial scan: ' .. tostring(result), vim.log.levels.WARN)
    return false
  end
  return result
end

--- Get current state
--- @return table
function M.get_state() return M.state end

return M
