local async = require('plenary.async')
local utils = require('CopilotChat.utils')
local curl = require('CopilotChat.utils.curl')
local files = require('CopilotChat.utils.files')
local file_cache = {}
local url_cache = {}

local M = {}

--- Get data for a file
---@param filename string
---@return string?, string?
function M.get_file(filename)
  local filetype = files.filetype(filename)
  if not filetype then
    return nil
  end
  local err, stat = async.uv.fs_stat(filename)
  if err or not stat then
    return nil
  end
  local modified = stat.mtime.sec

  local data = file_cache[filename]
  if not data or data._modified < modified then
    local content = files.read_file(filename)
    if not content or content == '' then
      return nil
    end
    data = {
      content = content,
      _modified = modified,
    }
    file_cache[filename] = data
  end

  return data.content, files.filetype_to_mimetype(filetype)
end

--- Get data for a buffer
---@param bufnr number
---@return string?, string?
function M.get_buffer(bufnr)
  if not utils.buf_valid(bufnr) then
    return nil
  end

  local content = vim.api.nvim_buf_get_lines(bufnr, 0, -1, false)
  if not content or #content == 0 then
    return nil
  end

  return table.concat(content, '\n'), files.filetype_to_mimetype(vim.bo[bufnr].filetype)
end

--- Get the content of an URL
---@param url string
---@return string?, string?
function M.get_url(url)
  if not url or url == '' then
    return nil
  end

  local ft = files.filetype(url)
  local content = url_cache[url]
  if not content then
    local ok, out = async.util.apcall(utils.system, { 'lynx', '-dump', url })
    if ok and out and out.code == 0 then
      -- Use lynx to fetch content
      content = out.stdout
    else
      -- Fallback to curl if lynx fails
      local response = curl.get(url, { raw = { '-L' } })
      if not response or not response.body then
        return nil
      end

      content = vim.trim(response
        .body
        -- Remove script, style tags and their contents first
        :gsub('<script.-</script>', '')
        :gsub('<style.-</style>', '')
        -- Remove XML/CDATA in one go
        :gsub('<!?%[?[%w%s]*%]?>', '')
        -- Remove all HTML tags (both opening and closing) in one go
        :gsub('<%/?%w+[^>]*>', ' ')
        -- Handle common HTML entities
        :gsub('&(%w+);', {
          nbsp = ' ',
          lt = '<',
          gt = '>',
          amp = '&',
          quot = '"',
        })
        -- Remove any remaining HTML entities (numeric or named)
        :gsub('&#?%w+;', ''))
    end

    url_cache[url] = content
  end

  return content, files.filetype_to_mimetype(ft)
end

return M
