---@diagnostic disable: missing-fields
---@class SelectaColorschemeConfig
---@field persist boolean Whether to persist colorscheme selection across sessions
---@field write_shada boolean Whether to write to ShaDa file after selection
---@field excluded_schemes string[] Additional colorschemes to exclude from the list

---@class SelectaColorschemeItem : SelectaItem
---@field text string The colorscheme name
---@field value string The colorscheme value
---@field icon string The icon to display
---@field kind string The kind of item (always "Colorscheme")

local M = {}
local fn = vim.fn
local fs = vim.fs
local uv = vim.uv or vim.loop

---@type NamuCoreConfig
M.config = {
  title = "  Namu Colorscheme ",
  persist = true,
  write_shada = false,
  excluded_schemes = {},
  movement = {
    next = { "<C-n>", "<DOWN>" },
    previous = { "<C-p>", "<UP>" },
    close = { "<ESC>" },
    select = { "<CR>" },
  },
  current_highlight = {
    enabled = true,
    hl_group = "NamuCurrentItem",
    prefix_icon = " ",
  },
  icon = "󱠦", -- 󱠦 -  -  -- 󰚟
}
local notify_opts = { title = "Namu", icon = M.config.icon }
local state = {
  original_win = nil,
  original_buf = nil,
  original_pos = nil,
}

---@param callback? fun(success: boolean, error_message?: string) Callback function after setup is complete
---@diagnostic disable-next-line: unused-local
local function setup_persistence(callback)
  local stdpath = fn.stdpath("config")
  ---@type string
  ---@diagnostic disable-next-line: param-type-mismatch
  local config_dir = fs.normalize(stdpath)
  local plugin_dir = fs.normalize(config_dir .. "/plugin")
  local namu_color_persist = fs.normalize(plugin_dir .. "/namu_colorscheme_persist.lua")

  -- Create plugin directory asynchronously
  uv.fs_mkdir(plugin_dir, 493, function(err) -- 493 is equivalent to 0755 permissions
    if err and err:match("^EEXIST") == nil then
      vim.schedule(function()
        vim.notify("Failed to create plugin directory: " .. err, vim.log.levels.ERROR, notify_opts)
      end)
      return
    end

    -- Check if file exists
    local file_exists = uv.fs_stat(namu_color_persist)
    if not file_exists then
      -- Get current colorscheme for initial setup
      local current_scheme = vim.g.colors_name or "default"

      local content = string.format(
        [[
-- Persisted colorscheme module (auto-generated by namu.nvim)
vim.g.NAMU_SCHEME = %q -- Initial colorscheme from setup

vim.api.nvim_create_autocmd("VimEnter", {
  callback = function()
    pcall(vim.cmd.colorscheme, vim.g.NAMU_SCHEME)
  end,
})

vim.api.nvim_create_autocmd("ColorScheme", {
  callback = function(params)
    vim.g.NAMU_SCHEME = params.match
  end,
})
]],
        current_scheme
      )

      -- Write file asynchronously
      uv.fs_open(namu_color_persist, "w", 438, function(open_err, fd) -- 438 is 0666 permissions
        if open_err then
          vim.schedule(function()
            vim.notify("Failed to create persistence file: " .. open_err, vim.log.levels.ERROR, notify_opts)
          end)
          return
        end

        uv.fs_write(fd, content, 0, function(write_err)
          if write_err then
            vim.schedule(function()
              vim.notify("Failed to write persistence file: " .. write_err, vim.log.levels.ERROR, notify_opts)
            end)
          end

          uv.fs_close(fd, function(close_err)
            if close_err then
              vim.schedule(function()
                vim.notify("Failed to close persistence file: " .. close_err, vim.log.levels.ERROR, notify_opts)
              end)
            end

            vim.schedule(function()
              vim.notify("Persistence setup complete", vim.log.levels.INFO, notify_opts)
            end)
          end)
        end)
      end)
    end
  end)
end

---@param opts? SelectaColorschemeConfig
function M.show(opts)
  opts = vim.tbl_deep_extend("force", M.config, opts or {})

  local win = vim.api.nvim_get_current_win()
  state = {
    original_win = win,
    original_buf = vim.api.nvim_get_current_buf(),
    original_pos = vim.api.nvim_win_get_cursor(win),
  }

  -- Get the current colorscheme
  local original_colorscheme = vim.g.colors_name
  -- Get a list of available colorschemes
  local colorschemes = vim.fn.getcompletion("", "color")

  -- stylua: ignore start
  local default_colorschemes = {
    "vim", "blue", "darkblue", "default", "delek", "desert", "elflord", "evening",
    "habamax", "industry", "koehler", "lunaperche", "morning", "murphy", "pablo",
    "peachpuff", "quiet", "ron", "shine", "slate", "torte", "zellner",
  }
  -- stylua: ignore end

  -- Filter out default colorschemes except "default"
  colorschemes = vim.tbl_filter(function(scheme)
    -- Include 'default' or exclude if it's in default_colorschemes or user's excluded_schemes
    return scheme == "default"
      or (not vim.tbl_contains(default_colorschemes, scheme) and not vim.tbl_contains(opts.excluded_schemes, scheme))
  end, colorschemes)

  -- Convert colorschemes into selecta-compatible items
  local items = vim.tbl_map(function(scheme)
    return {
      text = scheme,
      value = scheme,
      icon = "🎨",
      kind = "Colorscheme",
    }
  end, colorschemes)

  -- Find the index of the current colorscheme
  local initial_index = nil
  for i, item in ipairs(items) do
    if item.value == original_colorscheme then
      initial_index = i
      break
    end
  end

  local selecta = require("namu.selecta.selecta")
  selecta.pick(items, {
    title = "Select Colorscheme",
    initial_index = initial_index,
    display = {
      mode = "icon",
      padding = 1,
    },
    window = {
      border = "none",
      title_prefix = " ",
      auto_size = true,
      min_width = 20,
    },
    movement = vim.tbl_deep_extend("force", M.config.movement, {}),
    current_highlight = M.config.current_highlight,
    on_select = function(item)
      if item then
        pcall(vim.cmd.colorscheme, item.value)
        if opts.write_shada then
          vim.cmd("silent! wshada")
        end
        vim.notify("Colorscheme set to: " .. item.value, vim.log.levels.INFO, notify_opts)
      else
        vim.notify("No colorscheme selected.", vim.log.levels.WARN, notify_opts)
      end
      vim.api.nvim_set_current_win(state.original_win)
      vim.api.nvim_win_set_cursor(state.original_win, state.original_pos)
    end,
    on_cancel = function()
      vim.api.nvim_set_current_win(state.original_win)
      vim.api.nvim_win_set_cursor(state.original_win, state.original_pos)
      vim.cmd.colorscheme(original_colorscheme)
    end,
    on_move = function(item)
      if item then
        vim.wait(2, function()
          local ok, _ = pcall(vim.cmd.colorscheme, item.value)
          if not ok then
            vim.notify(("Cannot load colorscheme %s"):format(item.value), vim.log.levels.ERROR, notify_opts)
          end
        end)
      end
    end,
  })
end

---@param opts? SelectaColorschemeConfig
function M.setup(opts)
  opts = opts or {}
  M.config = vim.tbl_deep_extend("force", M.config, opts or {})

  -- Set up persistence if enabled
  if opts.persist then
    setup_persistence()
  end

  -- Create user command
  vim.api.nvim_create_user_command("Colorscheme", function()
    M.show(opts)
  end, {})
end

return M
