-- SQL CLI UI/Window Management Module
-- Functions for creating and managing UI windows and output

local utils = require('sql-cli.utils')
local table_nav = require('sql-cli.table_nav')

local M = {}

-- Load custom syntax patterns from config
local function load_custom_syntax_patterns(config)
  local patterns = {}

  -- First, try to load from external file if specified
  if config.syntax and config.syntax.custom_file then
    local expanded_path = vim.fn.expand(config.syntax.custom_file)
    local ok, loaded = pcall(dofile, expanded_path)
    if ok and type(loaded) == "table" then
      vim.list_extend(patterns, loaded)
    else
      vim.notify(
        string.format("Failed to load custom syntax file: %s", expanded_path),
        vim.log.levels.WARN
      )
    end
  end

  -- Then, add patterns from config (these override file patterns if same group)
  if config.syntax and config.syntax.patterns then
    vim.list_extend(patterns, config.syntax.patterns)
  end

  return patterns
end

-- Apply custom syntax pattern
local function apply_syntax_pattern(pattern_def)
  if not pattern_def.pattern or not pattern_def.group then
    return
  end

  -- Create syntax match
  local group_name = "SqlCli" .. pattern_def.group
  vim.cmd(string.format([[syntax match %s /%s/]], group_name, pattern_def.pattern))

  -- Apply colors if specified
  if pattern_def.color then
    local hl_parts = { "highlight", group_name }

    if pattern_def.color.gui then
      table.insert(hl_parts, string.format("guifg=%s", pattern_def.color.gui))
    end

    if pattern_def.color.cterm then
      table.insert(hl_parts, string.format("ctermfg=%s", pattern_def.color.cterm))
    end

    if pattern_def.color.bg_gui then
      table.insert(hl_parts, string.format("guibg=%s", pattern_def.color.bg_gui))
    end

    if pattern_def.color.bg_cterm then
      table.insert(hl_parts, string.format("ctermbg=%s", pattern_def.color.bg_cterm))
    end

    local attrs = {}
    if pattern_def.color.bold then table.insert(attrs, "bold") end
    if pattern_def.color.italic then table.insert(attrs, "italic") end
    if pattern_def.color.underline then table.insert(attrs, "underline") end

    if #attrs > 0 then
      table.insert(hl_parts, string.format("gui=%s", table.concat(attrs, ",")))
      table.insert(hl_parts, string.format("cterm=%s", table.concat(attrs, ",")))
    end

    vim.cmd(table.concat(hl_parts, " "))
  end
end

-- Create output window for SQL CLI results
function M.create_output_window(config, state)
  -- Save current window
  local current_win = vim.api.nvim_get_current_win()

  -- Create split
  local split_cmd = config.split.direction == "vertical" and "vsplit" or "split"
  vim.cmd(split_cmd)

  -- Resize window
  local size
  if config.split.direction == "vertical" then
    size = math.floor(vim.o.columns * config.split.size)
    vim.api.nvim_win_set_width(0, size)
  else
    size = math.floor(vim.o.lines * config.split.size)
    vim.api.nvim_win_set_height(0, size)
  end

  -- Create or reuse buffer for output
  local output_buf = state:get_output_buf()
  if not output_buf or not vim.api.nvim_buf_is_valid(output_buf) then
    output_buf = vim.api.nvim_create_buf(false, true)
    state:set_output_buf(output_buf)
    -- Try to set name, but handle if it already exists
    pcall(function()
      vim.api.nvim_buf_set_name(output_buf, "[SQL CLI Output]")
    end)

    -- Setup buffer-local keymaps for fuzzy filtering
    local opts = { buffer = output_buf, noremap = true, silent = true }

    -- <leader>sz to open fuzzy filter (z for zoom/fuzzy)
    vim.keymap.set('n', '<leader>sz', function()
      local fuzzy = require('sql-cli.fuzzy_filter')
      fuzzy.open_fuzzy_finder(output_buf)
    end, vim.tbl_extend("force", opts, { desc = "Fuzzy filter SQL results" }))

    -- Also map / for natural search behavior in output buffer
    vim.keymap.set('n', '/', function()
      local fuzzy = require('sql-cli.fuzzy_filter')
      fuzzy.open_fuzzy_finder(output_buf)
    end, vim.tbl_extend("force", opts, { desc = "Filter SQL results (fuzzy search)" }))

    -- <leader>sZ to reset filter (capital Z for reset/zoom out)
    vim.keymap.set('n', '<leader>sZ', function()
      local fuzzy = require('sql-cli.fuzzy_filter')
      fuzzy.reset_filter(output_buf)
    end, vim.tbl_extend("force", opts, { desc = "Reset result filter" }))
  end

  vim.api.nvim_win_set_buf(0, output_buf)
  local output_win = vim.api.nvim_get_current_win()
  state:set_output_win(output_win)

  -- Set buffer options
  vim.bo[output_buf].buftype = "nofile"
  vim.bo[output_buf].bufhidden = "hide"
  vim.bo[output_buf].swapfile = false
  vim.bo[output_buf].filetype = "sql-cli-output"  -- Use our custom syntax file
  -- Note: Don't clear syntax - let the filetype apply sql-cli-output.vim

  -- Apply our custom syntax highlighting (if needed for additional rules)
  M.setup_output_highlighting(config, state)

  -- Set window options
  vim.wo[output_win].wrap = config.output.wrap
  vim.wo[output_win].number = config.output.number
  vim.wo[output_win].relativenumber = false
  vim.wo[output_win].signcolumn = "no"
  vim.wo[output_win].foldcolumn = "0"

  -- Return to original window
  vim.api.nvim_set_current_win(current_win)
end

-- Toggle output window visibility
function M.toggle_output_window(config, state)
  if M.is_output_window_valid(state) then
    local output_win = state:get_output_win()
    vim.api.nvim_win_close(output_win, false)
    state:set_output_win(nil)
  else
    M.create_output_window(config, state)
  end
end

-- Check if output window is valid
function M.is_output_window_valid(state)
  local output_win = state:get_output_win()
  local output_buf = state:get_output_buf()
  return output_win
    and vim.api.nvim_win_is_valid(output_win)
    and output_buf
    and vim.api.nvim_buf_is_valid(output_buf)
end

-- Toggle split orientation
function M.toggle_split_orientation(config, state)
  -- Toggle the configuration
  if config.split.direction == "vertical" then
    config.split.direction = "horizontal"
    vim.notify("Split orientation: horizontal", vim.log.levels.INFO)
  else
    config.split.direction = "vertical"
    vim.notify("Split orientation: vertical", vim.log.levels.INFO)
  end

  -- If output window is open, recreate it with new orientation
  if M.is_output_window_valid(state) then
    -- Close current window
    local output_win = state:get_output_win()
    vim.api.nvim_win_close(output_win, false)
    state:set_output_win(nil)

    -- Recreate with new orientation
    M.create_output_window(config, state)
  end
end

-- Reset/recover output window layout to known-good state
-- This forcefully recreates the output window and clears corrupted state
function M.reset_output_layout(config, state)
  vim.notify("Resetting output layout...", vim.log.levels.INFO)

  -- Clear table navigation if active
  local table_nav = require('sql-cli.table_nav')
  if table_nav.is_active() then
    table_nav.disable_navigation()
  end

  -- Force close any existing output window (even if invalid)
  local output_win = state:get_output_win()
  if output_win and vim.api.nvim_win_is_valid(output_win) then
    pcall(function()
      vim.api.nvim_win_close(output_win, true)
    end)
  end

  -- Force delete any existing output buffer (even if corrupted)
  local output_buf = state:get_output_buf()
  if output_buf and vim.api.nvim_buf_is_valid(output_buf) then
    pcall(function()
      vim.api.nvim_buf_delete(output_buf, { force = true })
    end)
  end

  -- Clear state references
  state:set_output_win(nil)
  state:set_output_buf(nil)

  -- Recreate output window from scratch
  M.create_output_window(config, state)

  vim.notify("Output layout reset complete - try running your query again", vim.log.levels.INFO)
end

-- Preview query at cursor position in floating window
function M.preview_query_at_cursor(config)
  local bufnr = vim.api.nvim_get_current_buf()
  local cursor_line = vim.fn.line('.')
  local lines = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)

  -- Find query boundaries
  local start_line, end_line = utils.find_query_at_cursor(lines, cursor_line)

  if not start_line then
    vim.notify("No SQL statement found at cursor", vim.log.levels.WARN)
    return
  end

  -- Extract the query lines, skipping comments
  local query_lines = {}
  for i = start_line, end_line do
    local line = lines[i]
    -- Skip SQL comment lines
    if not line:match("^%s*%-%-") then
      table.insert(query_lines, line)
    end
  end

  -- Create floating window for preview
  local width = math.min(80, vim.o.columns - 10)
  local height = math.min(#query_lines + 4, vim.o.lines - 10)

  -- Calculate centered position
  local row = math.floor((vim.o.lines - height) / 2)
  local col = math.floor((vim.o.columns - width) / 2)

  -- Create buffer for preview
  local preview_buf = vim.api.nvim_create_buf(false, true)

  -- Add header
  local header = "─── Query Preview (press q or <Esc> to close) ───"
  local padding = math.floor((width - #header) / 2)
  vim.api.nvim_buf_set_lines(preview_buf, 0, -1, false, {
    string.rep(" ", padding) .. header,
    "",
  })

  -- Add query lines
  vim.api.nvim_buf_set_lines(preview_buf, -1, -1, false, query_lines)

  -- Add footer with line info
  local footer = string.format("Lines %d-%d (%d lines)", start_line, end_line, end_line - start_line + 1)
  vim.api.nvim_buf_set_lines(preview_buf, -1, -1, false, {
    "",
    string.rep(" ", math.floor((width - #footer) / 2)) .. footer,
  })

  -- Create floating window
  local win_opts = {
    relative = "editor",
    row = row,
    col = col,
    width = width,
    height = height,
    style = "minimal",
    border = "rounded",
    title = " SQL Query Preview ",
    title_pos = "center",
  }

  local preview_win = vim.api.nvim_open_win(preview_buf, true, win_opts)

  -- Set buffer options
  vim.api.nvim_buf_set_option(preview_buf, "bufhidden", "delete")
  vim.api.nvim_buf_set_option(preview_buf, "filetype", "sql")
  vim.api.nvim_buf_set_option(preview_buf, "modifiable", false)

  -- Set window options
  vim.api.nvim_win_set_option(preview_win, "cursorline", true)
  vim.api.nvim_win_set_option(preview_win, "wrap", false)

  -- Add keymaps to close preview
  local close_preview = function()
    if vim.api.nvim_win_is_valid(preview_win) then
      vim.api.nvim_win_close(preview_win, true)
    end
  end

  vim.keymap.set("n", "q", close_preview, { buffer = preview_buf })
  vim.keymap.set("n", "<Esc>", close_preview, { buffer = preview_buf })
  vim.keymap.set("n", "<CR>", function()
    close_preview()
    vim.notify("Use :SqlCliExecuteAtCursor or keybind to execute", vim.log.levels.INFO)
  end, { buffer = preview_buf, desc = "Close preview" })
end

-- Get statusline information
function M.statusline(state)
  local current_buf = vim.api.nvim_get_current_buf()
  local output_buf = state:get_output_buf()

  local status_parts = {}

  -- Show data file info
  local data_file = state:get_data_file()
  if data_file then
    local filename = vim.fn.fnamemodify(data_file, ":t")
    table.insert(status_parts, string.format("📄%s", filename))
  else
    table.insert(status_parts, "∅")
  end

  -- If we're in the output buffer, show table navigation info
  if output_buf and current_buf == output_buf then
    local multi_table_nav = require('sql-cli.multi_table_nav')
    local tables = multi_table_nav.find_all_tables(output_buf)

    if #tables > 1 then
      -- Find current table
      local win = vim.api.nvim_get_current_win()
      local cursor = vim.api.nvim_win_get_cursor(win)
      local current_line = cursor[1]
      local current_idx, _ = multi_table_nav.get_table_at_line(tables, current_line)

      if current_idx then
        table.insert(status_parts, string.format("📊%d/%d", current_idx, #tables))
      else
        table.insert(status_parts, string.format("📊-/%d", #tables))
      end
    elseif #tables == 1 then
      table.insert(status_parts, "📊1/1")
    end
  end

  return string.format("SQL[%s]", table.concat(status_parts, " "))
end

-- Setup output buffer syntax highlighting
function M.setup_output_highlighting(config, state, enable_nav)
  local output_buf = state:get_output_buf()
  if not output_buf or not vim.api.nvim_buf_is_valid(output_buf) then
    return
  end

  -- Apply highlighting in the output buffer
  vim.api.nvim_buf_call(output_buf, function()
    -- Clear any existing syntax first
    vim.cmd([[syntax clear]])

    -- Header and metadata
    vim.cmd([[syntax match SqlCliHeader /^--.*$/]])
    vim.cmd([[syntax match SqlCliSeparator /^[-─═]\+$/]])
    vim.cmd([[syntax match SqlCliExitCode /^-- Exit code:.*$/]])

    -- Table structure - must come before other patterns
    vim.cmd([[syntax match SqlCliTableBorder /[│├┤┌┐└┘─┬┴┼═╪╫╬]/]])
    vim.cmd([[syntax match SqlCliTablePipe /|/]])

    -- Success/Error messages - high priority
    vim.cmd([[syntax match SqlCliSuccess /^#.*Query completed:.*$/]])
    vim.cmd([[syntax match SqlCliError /^ERROR:.*$/]])
    vim.cmd([[syntax match SqlCliError /Error:.*$/]])

    -- Currency symbols and formatted money (high priority, before numbers)
    vim.cmd([[syntax match SqlCliCurrency /[$£€¥₹¤]\S*/]])
    vim.cmd([[syntax match SqlCliCurrency /\S*\s\+\(USD\|EUR\|GBP\|JPY\|CHF\|CNY\|INR\|AUD\|CAD\|SEK\|NOK\|DKK\)\>/]])

    -- Number patterns - order matters for precedence
    -- Use word boundaries \< \> to avoid matching inside alphanumeric IDs like ORD012234

    -- Compact numbers (1.5k, 2M, etc) - highest priority
    vim.cmd([[syntax match SqlCliCompactNumber /\v<\d+\.?\d*[kMBT]>/ contains=NONE]])

    -- Numbers with thousand separators (1,234.56)
    vim.cmd([[syntax match SqlCliFormattedNumber /\v<\d{1,3}([,.']\d{3})+\.?\d*>/ contains=NONE]])

    -- Decimal numbers (must have decimal point)
    vim.cmd([[syntax match SqlCliDecimalNumber /\v<\d+\.\d+>/ contains=NONE]])

    -- Plain integers (standalone only)
    vim.cmd([[syntax match SqlCliNumber /\v<\d+>/ contains=NONE]])

    -- Special values
    vim.cmd([[syntax match SqlCliNull /\<NULL\>/]])
    vim.cmd([[syntax match SqlCliBoolean /\<\(true\|false\|TRUE\|FALSE\)\>/]])

    -- Load and apply custom syntax patterns from config
    local custom_patterns = load_custom_syntax_patterns(config)
    for _, pattern in ipairs(custom_patterns) do
      apply_syntax_pattern(pattern)
    end

    -- Quoted strings (lowest priority)
    vim.cmd([[syntax match SqlCliString /"[^"]*"/]])
    vim.cmd([[syntax match SqlCliString /'[^']*'/]])

    -- Define highlight colors with better contrast
    vim.cmd([[highlight SqlCliHeader guifg=#6272a4 ctermfg=60]])
    vim.cmd([[highlight SqlCliSeparator guifg=#44475a ctermfg=238]])
    vim.cmd([[highlight SqlCliTableBorder guifg=#6272a4 ctermfg=61]])
    vim.cmd([[highlight SqlCliTablePipe guifg=#6272a4 ctermfg=61]])

    -- Numbers and currency with distinct colors
    vim.cmd([[highlight SqlCliNumber guifg=#bd93f9 ctermfg=141]])
    vim.cmd([[highlight SqlCliDecimalNumber guifg=#bd93f9 ctermfg=141]])
    vim.cmd([[highlight SqlCliFormattedNumber guifg=#bd93f9 ctermfg=141]])
    vim.cmd([[highlight SqlCliCompactNumber guifg=#ff79c6 ctermfg=212]])
    vim.cmd([[highlight SqlCliCurrency guifg=#50fa7b ctermfg=84]])

    -- Special values
    vim.cmd([[highlight SqlCliNull guifg=#ff79c6 ctermfg=212 gui=italic cterm=italic]])
    vim.cmd([[highlight SqlCliBoolean guifg=#8be9fd ctermfg=117]])

    -- Status messages
    vim.cmd([[highlight SqlCliError guifg=#ff5555 ctermfg=203 gui=bold cterm=bold]])
    vim.cmd([[highlight SqlCliSuccess guifg=#50fa7b ctermfg=84]])
    vim.cmd([[highlight SqlCliExitCode guifg=#6272a4 ctermfg=60]])

    -- Strings with subdued color
    vim.cmd([[highlight SqlCliString guifg=#f1fa8c ctermfg=228]])

    -- Custom syntax pattern colors are applied by apply_syntax_pattern() above
  end)

  -- Note: Table navigation is now enabled in executor.lua after query completes
  -- This ensures the buffer is fully populated with results
end

return M