local M = {}

local conf = require('fff.conf')
local layout = require('fff.layout')
local list_separator = require('fff.list_separator')
local scrollbar = require('fff.scrollbar')
local preview = require('fff.file_picker.preview')
local picker_ui_state = require('fff.picker_ui.picker_ui_state')

-- Parent module reference (set by picker_ui.lua during initialization).
---@type table
local P = nil

function M.init(parent_module) P = parent_module end

local S = picker_ui_state.state

local function restore_paste(should_restore)
  if should_restore then vim.o.paste = true end
end

function M.relayout()
  if not P.state.active then return end

  local config = S.config
  if not config then return end

  local computed_layout = layout.compute(config, conf.preview_enabled(config))
  local win_configs = computed_layout.win_configs
  S.layout = computed_layout.layout
  S.preview_visible = computed_layout.preview_visible

  if S.list_win and vim.api.nvim_win_is_valid(S.list_win) then
    vim.api.nvim_win_set_config(S.list_win, win_configs.list)
  end

  if S.input_win and vim.api.nvim_win_is_valid(S.input_win) then
    vim.api.nvim_win_set_config(S.input_win, win_configs.input)
  end

  local preview_win_alive = S.preview_win and vim.api.nvim_win_is_valid(S.preview_win)
  if S.preview_visible and win_configs.preview then
    if preview_win_alive then
      vim.api.nvim_win_set_config(S.preview_win, win_configs.preview)
    else
      P.open_preview(win_configs.preview)
    end
  elseif preview_win_alive then
    P.close_preview()
  end

  local file_info_win_alive = S.file_info_win and vim.api.nvim_win_is_valid(S.file_info_win)
  if win_configs.file_info then
    if file_info_win_alive then
      vim.api.nvim_win_set_config(S.file_info_win, win_configs.file_info)
    else
      S.file_info_buf = vim.api.nvim_create_buf(false, true)
      vim.api.nvim_set_option_value('bufhidden', 'wipe', { buf = S.file_info_buf })
      vim.api.nvim_set_option_value('buftype', 'nofile', { buf = S.file_info_buf })
      vim.api.nvim_set_option_value('filetype', 'fff_file_info', { buf = S.file_info_buf })
      vim.api.nvim_set_option_value('modifiable', false, { buf = S.file_info_buf })
      S.file_info_win = vim.api.nvim_open_win(S.file_info_buf, false, win_configs.file_info)
    end
  elseif file_info_win_alive then
    vim.api.nvim_win_close(S.file_info_win, true)
    S.file_info_win = nil
    if S.file_info_buf and vim.api.nvim_buf_is_valid(S.file_info_buf) then
      vim.api.nvim_buf_delete(S.file_info_buf, { force = true })
    end
    S.file_info_buf = nil
  end

  P.render_list()
  P.update_preview()
  P.update_status()
end

function M.close()
  if not P.state.active then return end

  vim.cmd('stopinsert')
  P.state.active = false

  restore_paste(S.restore_paste)

  list_separator.cleanup()
  scrollbar.cleanup()

  local ts_ok, ts_hl = pcall(require, 'fff.treesitter_hl')
  if ts_ok then ts_hl.cleanup() end

  local windows = { S.input_win, S.list_win, S.preview_win }
  if S.file_info_win then table.insert(windows, S.file_info_win) end

  for _, win in ipairs(windows) do
    if win and vim.api.nvim_win_is_valid(win) then vim.api.nvim_win_close(win, true) end
  end

  local buffers = { S.input_buf, S.list_buf, S.file_info_buf }
  if S.preview_buf then buffers[#buffers + 1] = S.preview_buf end

  for _, buf in ipairs(buffers) do
    if buf and vim.api.nvim_buf_is_valid(buf) then
      vim.api.nvim_buf_clear_namespace(buf, -1, 0, -1)
      if buf == S.preview_buf then preview.clear_buffer(buf) end
      vim.api.nvim_buf_delete(buf, { force = true })
    end
  end

  P.close_preview_timer()

  S.input_win = nil
  S.list_win = nil
  S.file_info_win = nil
  S.preview_win = nil
  S.input_buf = nil
  S.list_buf = nil
  S.file_info_buf = nil
  S.preview_buf = nil
  S.preview_visible = false
  S.items = {}
  S.filtered_items = {}
  S.line_to_item = {}
  S.item_to_lines = {}
  S.last_render_ctx = nil
  S.cursor = 1
  S.query = ''
  S.ns_id = nil
  S.last_preview_file = nil
  S.last_preview_location = nil
  S.current_file_cache = nil
  S.location = nil
  S.selected_files = {}
  S.selected_file_order = {}
  S.selected_items = {}
  S.mode = nil
  S.grep_config = nil
  S.grep_mode = 'plain'
  S.grep_regex_fallback_error = nil
  S.suggestion_items = nil
  S.suggestion_source = nil
  S.renderer = nil
  S.restore_paste = false
  S.combo_visible = true
  S.combo_initial_cursor = nil
  P.reset_history_state()
  pcall(vim.api.nvim_del_augroup_by_name, 'fff_picker_focus')
end

return M
