local cmd = vim.api.nvim_command
local M = {}

local c = require('themes.nord.colors')
local hi = require('util').highlight

-- Set terminal colors
function M.set_vim_termcolors()
    vim.g.terminal_color_0 = c.grey1
    vim.g.terminal_color_1 = c.red
    vim.g.terminal_color_2 = c.green
    vim.g.terminal_color_3 = c.yellow
    vim.g.terminal_color_4 = c.blue
    vim.g.terminal_color_5 = c.purple
    vim.g.terminal_color_6 = c.cyan
    vim.g.terminal_color_7 = c.white1
    vim.g.terminal_color_8 = c.grey_bright
    vim.g.terminal_color_9 = c.red
    vim.g.terminal_color_10 = c.green
    vim.g.terminal_color_11 = c.yellow
    vim.g.terminal_color_12 = c.blue
    vim.g.terminal_color_13 = c.purple
    vim.g.terminal_color_14 = c.teal
    vim.g.terminal_color_15 = c.white2
end

-- Editor related groups
function M.highlight_editor()
    -- Editor
    hi('NormalFloat', c.fg    , c.grey2, '', '')
    hi('ColorColumn', ''      , c.grey1, '', '')
    hi('Cursor'     , c.black , c.fg   , '', '')
    hi('CursorIM'   , c.black , c.white1, '', '')
    hi('CursorLine' , ''      , c.grey1, '', '')
    hi('TermCursorNC', ''     , c.grey1, '', '')
    hi('Underlined' , c.green , ''     , 'underline', '')
    hi('Ignore'     , c.grey1 , ''     , '', '')
    hi('Error'      , c.fg    , c.red  , '', '')
    hi('LineNr'     , c.grey3 , ''     , '', '')
    hi('MatchParen' , c.cyan  , c.grey3, '', '')
    hi('NonText'    , c.highlight, ''     , '', '')
    hi('EndOfBuffer', c.black , ''      , '', '') -- hide filler line ~ completely
    hi('Normal'     , c.fg    , c.black, '', '')
    hi('Pmenu'      , c.fg    , c.grey2, '', '')
    hi('PmenuSbar'  , c.fg    , c.grey2, '', '')
    hi('PmenuSel'   , c.cyan  , c.grey3, '', '')
    hi('PmenuThumb' , c.cyan  , c.grey3, '', '')
    hi('SpecialKey' , c.grey3 , ''     , '', '')
    hi('SpellBad'   , c.red   , c.black, 'undercurl', c.red)
    hi('SpellCap'   , c.yellow, c.black, 'undercurl', c.yellow)
    hi('SpellLocal' , c.white1, c.black, 'undercurl', c.white1)
    hi('SpellRare'  , c.white2, c.black, 'undercurl', c.white2)
    hi('Visual'     , ''      , c.grey2 , '', '')
    hi('VisualNOS'  , ''      , c.grey2 , '', '')

    -- quickfix
    hi('QuickFixLine' , ''     , c.blue  , '', '')
    hi('qfLineNr'     , c.yellow, ''      , '', '')

    -- :checkhealth
    hi('healthError'  , c.red   , c.grey1, '', '')
    hi('healthSuccess', c.green , c.grey1, '', '')
    hi('healthWarning', c.yellow, c.grey1, '', '')

    -- Gutter
    hi('CursorColumn', ''     , c.grey1, '', '')
    hi('CursorLineNr', c.fg   , ''     , '', '')
    hi('Folded'      , c.grey3, c.grey1, '', '')
    hi('FoldColumn'  , c.grey3, c.black, '', '')
    hi('SignColumn'  , c.grey1, c.black, '', '')

    -- Navigation
    hi('Directory', c.cyan, '', '', '')

    -- Prompt
    hi('ErrorMsg'   , c.fg   , c.red   , '', '')
    hi('ModeMsg'    , c.fg   , ''      , '', '')
    hi('MoreMsg'    , c.cyan , ''      , '', '')
    hi('Question'   , c.fg   , ''      , '', '')
    hi('WarningMsg' , c.black, c.yellow, '', '')
    hi('WildMenu'   , c.cyan , c.grey1 , '', '')

    -- Statusline
    hi('StatusLine'      , c.cyan, c.grey3, '', '')
    hi('StatusLineNC'    , c.fg  , c.grey3, '', '')
    hi('StatusLineTerm'  , c.cyan, c.grey3, '', '')
    hi('StatusLineTermNC', c.fg  , c.grey3, '', '')

    -- Search
    hi('IncSearch', c.white2, c.dark_blue, 'underline', '')
    hi('Search'   , c.grey1 , c.cyan     , ''         , '')

    -- Tabline
    hi('TabLine'    , c.fg  , c.grey1, '', '')
    hi('TabLineFill', c.fg  , c.grey1, '', '')
    hi('TabLineSel' , c.cyan, c.grey3, '', '')

    -- Window
    hi('Title', c.fg, '', '', '')
    hi('VertSplit', c.grey2, c.black, '', '')
end

-- Syntax groups
function M.highlight_syntax()
    -- Base syntax
    hi('Boolean', c.blue, '', '', '')
    hi('Character', c.fg, '', '', '')
    hi('Comment', c.grey_bright, '', 'italic', '')
    hi('Conceal', '', '', '', '')
    hi('Conditional', c.blue, '', '', '')
    hi('Constant', c.fg, '', '', '')
    hi('Define', c.blue, '', '', '')
    hi('Delimiter', c.white2, '', '', '')
    hi('Exception', c.blue, '', '', '')
    hi('Float', c.purple, '', '', '')
    hi('Function', c.cyan, '', '', '')
    hi('Identifier', c.fg, '', '', '')
    hi('Include', c.blue, '', '', '')
    hi('Keyword', c.blue, '', 'bold', '')
    hi('Label', c.blue, '', '', '')
    hi('Number', c.purple, '', '', '')
    hi('Operator', c.blue, '', '', '')
    hi('PreProc', c.blue, '', '', '')
    hi('Repeat', c.blue, '', '', '')
    hi('Special', c.fg, '', '', '')
    hi('SpecialChar', c.yellow, '', '', '')
    hi('SpecialComment', c.cyan, '', 'italic', '')
    hi('Statement', c.blue, '', '', '')
    hi('StorageClass', c.blue, '', '', '')
    hi('String', c.green, '', '', '')
    hi('Structure', c.blue, '', '', '')
    hi('Tag', c.fg, '', '', '')
    hi('Todo', c.yellow, '', '', '')
    hi('Type', c.orange, '', '', '')
    hi('Typedef', c.blue, '', '', '')
    cmd('hi! link Macro Define')
    cmd('hi! link PreCondit PreProc')
    cmd('hi! link Variable Identifier')

    -- Diff
    hi('DiffAdd'   , c.green , c.grey1, '', '')
    hi('DiffChange', c.yellow, c.grey1, '', '')
    hi('DiffDelete', c.red   , c.grey1, '', '')
    hi('DiffText'  , c.blue  , c.grey1, '', '')
    -- Legacy diff groups for some plugins
    hi('diffOldFile', c.dark_blue, c.grey1, '', '')
    hi('diffNewFile', c.blue, c.grey1, '', '')
    hi('diffFile', c.cyan, c.grey1, '', '')
    hi('diffLine', c.purple, c.grey1, '', '')
    hi('diffIndexLine', c.fg, c.grey1, '', '')
    cmd('hi! link diffAdded DiffAdd')
    cmd('hi! link diffRemoved DiffDelete')
    cmd('hi! link diffChanged DiffChange')
end

-- Things that still don't look right with nvim-treesitter
function M.highlight_languages()
    -- sql
    cmd('hi! link sqlKeyword Keyword')
    cmd('hi! link sqlSpecial Keyword')

    -- markdown
    hi('markdownCode', c.fg, '', 'italic', '')
    hi('markdownCodeBlock', c.fg, '', 'italic', '')
    hi('markdownH1', c.purple, '', 'bold', '')
    cmd('hi! link markdownH1Delimiter markdownH1')
    hi('markdownH2', c.dark_blue, '', 'bold', '')
    cmd('hi! link markdownH2Delimiter markdownH2')
    hi('markdownH3', c.blue, '', 'bold', '')
    cmd('hi! link markdownH3Delimiter markdownH3')
    hi('markdownH4', c.cyan, '', 'bold', '')
    cmd('hi! link markdownH4Delimiter markdownH4')
    hi('markdownH5', c.teal, '', 'bold', '')
    cmd('hi! link markdownH5Delimiter markdownH5')
    hi('markdownH6', c.green, '', 'bold', '')
    cmd('hi! link markdownH6Delimiter markdownH6')

    -- html
    hi('htmlLink', c.green, '', 'underline', '')
    cmd('hi! link htmlH1 markdownH1')
    cmd('hi! link htmlH2 markdownH2')
    cmd('hi! link htmlH3 markdownH3')
    cmd('hi! link htmlH4 markdownH4')
    cmd('hi! link htmlH5 markdownH5')
    cmd('hi! link htmlH6 markdownH6')
end

-- Treesitter (:h nvim-treesitter-highlights)
function M.highlight_treesitter()
    hi('TSAnnotation', c.dark_blue, '', 'italic', '')
    hi('TSCharacter', c.green, '', '', '')
    hi('TSConstructor', c.blue, '', '', '')
    hi('TSConstant', c.yellow, '', '', '')
    hi('TSFloat', c.purple, '', '', '')
    hi('TSNumber', c.purple, '', '', '')
    hi('TSString', c.green, '', '', '')

    hi('TSAttribute', c.purple, '', '', '')
    cmd('hi! link TSBoolean Boolean')
    hi('TSConstBuiltin', c.teal, '', '', '')
    hi('TSConstMacro', c.teal, '', '', '')
    hi('TSError', c.red, '', '', '')
    hi('TSException', c.purple, '', '', '')
    hi('TSField', c.teal, '', '', '')
    hi('TSFuncMacro', c.teal, '', '', '')
    hi('TSInclude', c.blue, '', '', '')
    hi('TSLabel', c.purple, '', '', '')
    hi('TSNamespace', c.fg, '', '', '')
    hi('TSOperator', c.blue, '', '', '')
    hi('TSParameter', c.purple, '', 'italic', '')
    hi('TSParameterReference', c.purple, '', 'italic', '')
    hi('TSProperty', c.teal, '', '', '')
    hi('TSPunctDelimiter', c.fg, '', '', '')
    hi('TSPunctBracket', c.cyan, '', '', '')
    hi('TSPunctSpecial', c.cyan, '', '', '')
    hi('TSStringRegex', c.teal, '', '', '')
    hi('TSStringEscape', c.purple, '', '', '')
    hi('TSSymbol', c.purple, '', '', '')
    hi('TSType', c.orange, '', '', '')
    hi('TSTypeBuiltin', c.orange, '', '', '')
    hi('TSTag', c.fg, '', '', '')
    hi('TSTagDelimiter', c.purple, '', '', '')
    hi('TSText', c.fg, '', '', '')
    hi('TSTextReference', c.purple, '', '', '')
    hi('TSStrong' , c.fg, '', 'bold', '')
    hi('TSEmphasis', c.fg, '', 'bold,italic', '')
    hi('TSUnderline', '', '', 'underline', '')
    hi('TSTitle', c.dark_blue, '', 'bold', '')
    hi('TSLiteral', c.fg, '', '', '')
    hi('TSURI', c.green, '', 'underline', '')

    cmd('hi! link TSComment Comment')
    hi('TSConditional', c.blue, '', 'bold', '')
    hi('TSKeyword', c.blue, '', 'bold', '')
    hi('TSRepeat', c.blue, '', 'bold', '')
    hi('TSKeywordFunction', c.blue, '', 'bold', '')
    hi('TSKeywordOperator', c.blue, '', 'bold', '')
    cmd('hi! link TSFunction Function')
    hi('TSMethod', c.teal, '', '', '')
    cmd('hi! link TSFuncBuiltin Function')
    cmd('hi! link TSVariable Variable')
    cmd('hi! link TSVariableBuiltin Variable')
    cmd('hi! link TSStructure Structure')

    hi('TSNote', c.blue, '', 'bold', '')
    hi('TSWarning', c.yellow, '', 'bold', '')
    hi('TSDanger', c.red, '', 'bold', '')
end

-- LSP groups
function M.highlight_lsp()
    hi('LspDiagnosticsDefaultError', c.red, '', '', '')
    hi('LspDiagnosticsSignError', c.red, '', '', '')
    hi('LspDiagnosticsFloatingError', c.red, '', '', '')
    hi('LspDiagnosticsVirtualTextError', c.red, '', 'italic', '')
    hi('LspDiagnosticsUnderlineError', '', '', 'undercurl', c.red)

    hi('LspDiagnosticsDefaultWarning', c.yellow, '', '', '')
    hi('LspDiagnosticsSignWarning', c.yellow, '', '', '')
    hi('LspDiagnosticsFloatingWarning', c.yellow, '', '', '')
    hi('LspDiagnosticsVirtualTextWarning', c.yellow, '', 'italic', '')
    hi('LspDiagnosticsUnderlineWarning', '', '', 'undercurl', c.yellow)

    hi('LspDiagnosticsDefaultInformation', c.blue, '', '', '')
    hi('LspDiagnosticsSignInformation', c.blue, '', '', '')
    hi('LspDiagnosticsFloatingInformation', c.blue, '', '', '')
    hi('LspDiagnosticsVirtualTextInformation', c.blue, '', 'italic', '')
    hi('LspDiagnosticsUnderlineInformation', '', '', 'undercurl', c.blue)

    hi('LspDiagnosticsDefaultHint', c.cyan, '', '', '')
    hi('LspDiagnosticsSignHint', c.cyan, '', '', '')
    hi('LspDiagnosticsFloatingHint', c.cyan, '', '', '')
    hi('LspDiagnosticsVirtualTextHint', c.cyan, '', 'italic', '')
    hi('LspDiagnosticsUnderlineHint', '', '', 'undercurl', c.cyan)

    hi('LspReferenceText', c.fg, c.grey_bright, '', '')
    hi('LspReferenceRead', c.fg, c.grey_bright, '', '')
    hi('LspReferenceWrite', c.fg, c.grey_bright, '', '')
    cmd('hi! link LspCodeLens Comment')
end

-- Specify groups for plugins
function M.highlight_plugins()
    -- nvim-cmp
    hi('CmpItemAbbr', c.fg, '', '', '')
    hi('CmpItemAbbrMatch', c.yellow, '', '', '')
    hi('CmpItemAbbrMatchFuzzy', c.yellow, '', '', '')
    hi('CmpItemKind', c.orange, '', '', '')
    hi('CmpItemMenu', c.blue, '', '', '')

    -- LuaSnip
    hi('LuaSnipChoice', c.orange, '', '', '')
    hi('LuaSnipInsert', c.blue, '', '', '')

    -- Gitsigns
    hi('GitSignsAddNr'   , c.green , '', '', '')
    hi('GitSignsChangeNr', c.yellow, '', '', '')
    hi('GitSignsDeleteNr', c.red   , '', '', '')
    hi('GitSignsCurrentLineBlame', c.grey_bright, '', 'italic,bold', '')

    -- dap.nvim
    hi('DapSignDefault', c.orange, '', '', '')
    hi('DapSignRejected', c.red, '', '', '')

    -- ts-rainbow
    hi('rainbowcol1', c.red, '', 'bold', '')
    hi('rainbowcol2', c.orange, '', 'bold', '')
    hi('rainbowcol3', c.yellow, '', 'bold', '')
    hi('rainbowcol4', c.green, '', 'bold', '')
    hi('rainbowcol5', c.cyan, '', 'bold', '')
    hi('rainbowcol6', c.blue, '', 'bold', '')
    hi('rainbowcol7', c.purple, '', 'bold', '')

    -- hop.nvim
    hi('HopNextKey', c.red, '', 'bold', '')
    hi('HopNextKey1', c.cyan, '', 'bold', '')
    hi('HopNextKey2', c.dark_blue, '', '', '')
    cmd('hi! link HopUnmatched LineNr')

    -- vim-eft
    hi('EftChar', c.orange, '', 'bold,underline', '')
    cmd('hi! link EftSubChar LineNr')

    -- dashboard-nvim / alpha-nvim
    hi('DashboardHeader'  , c.blue       , '', 'bold'       , '')
    hi('DashboardCenter'  , c.green      , '', 'bold'       , '')
    hi('DashboardShortcut', c.grey_bright, '', 'bold,italic', '')
    hi('DashboardFooter'  , c.purple     , '', 'bold'       , '')

    -- symbols-outline.nvim
    hi('FocusedSymbol', c.black, c.yellow, 'bold', '')

    -- NvimTree
    hi('NvimTreeIndentMarker'   , c.grey3      , '', '', '')
    hi('NvimTreeFolderIcon'     , c.fg         , '', '', '')
    hi('NvimTreeRootFolder'     , c.teal       , '', 'bold', '')
    hi('NvimTreeFolderName'     , c.blue       , '', '', '')
    hi('NvimTreeEmptyFolderName', c.grey_bright, '', '', '')
    hi('NvimTreeImageFile'      , c.yellow     , '', '', '')
    hi('NvimTreeExecFile'       , c.green      , '', '', '')
    hi('NvimTreeSpecialFile'    , c.dark_blue  , '', 'underline', '')
    hi('NvimTreeGitDirty'       , c.yellow     , '', '', '')
    hi('NvimTreeGitNew'         , c.green      , '', '', '')
    hi('NvimTreeGitDeleted'     , c.red        , '', '', '')

    -- WhichKey
    hi('WhichKey'         , c.green      , '', 'bold', '')
    hi('WhichKeyGroup'    , c.cyan       , '', ''    , '')
    hi('WhichKeyDesc'     , c.blue       , '', ''    , '')
    hi('WhichKeySeperator', c.grey3      , '', ''    , '')
    hi('WhichKeyFloating' , c.fg         , '', ''    , '')
    hi('WhichKeyFloat'    , c.grey_bright, '', ''    , '')

    -- Indent Blankline
    hi('IndentBlanklineChar', c.grey1, '', '', '')
    hi('IndentBlanklineContextChar', c.grey_bright, '', '', '')

    -- window-picker.nvim
    hi('WindowPicker', c.fg, c.blue, 'bold', '')
    hi('WindowPickerSwap', c.fg, c.orange, 'bold', '')

    -- vim-illuminate
    hi('illuminatedWord', '', '', 'underline', '')
    hi('illuminatedCurWord', '', '', 'underline', '')

    -- trouble.nvim
    hi('LspTroubleText', c.blue, '', 'bold', '')

    -- Telescope
    hi('TelescopePromptBorder', c.cyan, '', 'bold', '')
    hi('TelescopeResultsBorder', c.blue, '', 'bold', '')
    hi('TelescopePreviewBorder', c.green, '', 'bold', '')
    hi('TelescopeSelection', c.fg, c.grey2, '', '')
    hi('TelescopeMultiSelection', c.fg, c.grey2, 'bold', '')
    hi('TelescopeSelectionCaret', c.red, c.grey2, 'bold', '')
    hi('TelescopeMatching', c.yellow, '', 'bold', '')

    -- Neogit
    hi('NeogitBranch', c.purple, '', '', '')
    hi('NeogitRemote', c.blue, '', '', '')
    hi('NeogitHunkHeader', c.cyan, c.grey2, 'bold', '')
    hi('NeogitHunkHeaderHighlight', c.yellow, c.grey2, 'bold', '')
    hi('NeogitDiffContextHighlight', c.fg, c.grey2, '', '')
    hi('NeogitDiffDeleteHighlight', c.red, c.grey2, '', '')
    hi('NeogitDiffAddHighlight', c.green, c.grey2, '', '')
    hi('NeogitNotificationInfo', c.green, '', '', '')
    hi('NeogitNotificationWarning', c.yellow, '', '', '')
    hi('NeogitNotificationError', c.red, '', '', '')
end

return M
