let g:hg_format_command = ""


function PopupCommand(command)
	let buf = term_start(a:command, {'hidden': 1, 'term_finish': 'close'})
	let winid = popup_create(buf, {'minwidth': 120, 'minheight': 28})
endfunction

function! ExecuteCommand(command)
  " a:command is a shell command string, e.g. 'hg status'
  return system(a:command . ' 2>&1')
endfunction

function! s:CommitWithFormat()
  wa
  if exists("g:hg_format_command") && !empty(g:hg_format_command)
    execute '!'.g:hg_format_command
  endif
  execute 
  call ExecuteCommand('!hg addremove')
  call PopupCommand('hg commit')
endfunction

function! s:OpenHgDiff(file)
  let l:current_file = a:file !=# '' ? a:file : expand('%')
  let l:filetype = &filetype
  let l:temp_file = tempname()
  let l:command = 'hg cat -r . ' . l:current_file . ' > ' . l:temp_file
  call ExecuteCommand(l:command)
  execute 'tabe ' . l:temp_file
  execute 'setfiletype' l:filetype
  setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile 
  execute 'vert diffsplit' l:current_file
endfunction

command HGDiff call s:OpenHgDiff(expand('%'))
command! HGCommit call <SID>HgCommitUI()
" command Commit call s:CommitWithFormat()
" map <C-k> :Commit<CR>
"

nnoremap <Leader>df :HGDiff<CR>
nnoremap <C-k> :HGCommit<CR>



" HG UI
function! s:HgCommitUI()
  " Save current window to go back if needed
  let l:save_winid = win_getid()

  " Get hg status
  let l:status = ExecuteCommand('hg status -T"[ ] {status} {path}\n"')
  if v:shell_error != 0
    echohl ErrorMsg
    echom "hg status failed:"
    echom l:status
    echohl None
    return
  endif
  let l:lines = split(l:status, "\n")
  if empty(l:lines)
    echo "No changes to commit."
    return
  endif

  " Open a new tab for this commit UI
  tabnew
  " Top window for file selection
  enew
  let b:hgcommit_type = 'filelist'
  call setline(1, s:FormatHgStatusLines(l:lines))
  setlocal buftype=acwrite bufhidden=wipe nobuflisted noswapfile
  setlocal nomodifiable
  setlocal cursorline
  nnoremap <silent> <buffer> <CR> :call <SID>ToggleHgFileSelection()<CR>
  nnoremap <silent> <buffer> <leader>aa :call <SID>ToggleHgSelectAll()<CR>

  " Split for commit message
  belowright split
  resize 10
  enew
  let b:hgcommit_type = 'message'
  setlocal buftype=acwrite bufhidden=wipe nobuflisted noswapfile
  " Optional: initial comment
  call setline(1, ['# Enter commit message above. Lines starting with # are ignored.'])
  " Map to commit
  nnoremap <silent> <buffer> <leader>cc :call <SID>DoHgCommit()<CR>

  " Go back to top window to start there
  wincmd k
endfunction

function! s:FormatHgStatusLines(lines) abort
  let l:out = []
  for l in a:lines
    if empty(l)
      continue
    endif
    " Typical hg status line: "M path/to/file"
    " We keep status char and the rest of line, but prepend [ ]
    call add(l:out, l)
  endfor
  return l:out
endfunction

function! s:ToggleHgFileSelection() abort
  if get(b:, 'hgcommit_type', '') !=# 'filelist'
    return
  endif
  setlocal modifiable
  let l:lnum = line('.')
  let l:line = getline(l:lnum)
  if l:line =~# '^\[ \]'
    " select
    let l:line = substitute(l:line, '^\[ \]', '[x]', '')
  elseif l:line =~# '^\[x\]'
    " unselect
    let l:line = substitute(l:line, '^\[x\]', '[ ]', '')
  endif
  call setline(l:lnum, l:line)
  setlocal nomodifiable
endfunction


function! s:ToggleHgSelectAll() abort
  if get(b:, 'hgcommit_type', '') !=# 'filelist'
    return
  endif
  setlocal modifiable
  let l:lines = getline(1, '$')

  " Decide if we're selecting all or deselecting all:
  let l:any_unselected = 0
  for l:l in l:lines
    if l:l =~# '^\[ \]'
      let l:any_unselected = 1
      break
    endif
  endfor

  let l:new = []
  if l:any_unselected
    " select all
    for l:l in l:lines
      if l:l =~# '^\[ \]'
        call add(l:new, substitute(l:l, '^\[ \]', '[x]', ''))
      else
        call add(l:new, l:l)
      endif
    endfor
  else
    " deselect all
    for l:l in l:lines
      if l:l =~# '^\[x\]'
        call add(l:new, substitute(l:l, '^\[x\]', '[ ]', ''))
      else
        call add(l:new, l:l)
      endif
    endfor
  endif

  call setline(1, l:new)
  setlocal nomodifiable
endfunction


function! s:GetSelectedHgFiles() abort
  " Find the filelist buffer in this tab
  let l:files = []
  for l:w in range(1, winnr('$'))
    execute l:w . 'wincmd w'
    if get(b:, 'hgcommit_type', '') ==# 'filelist'
      let l:lines = getline(1, '$')
      for l:L in l:lines
        if l:L =~# '^\[x\] '
          " Format: "[x] X path/to/file"
          " Strip "[x] "
          let l:rest = substitute(l:L, '^\[x\] ', '', '')
          " First char is hg status, then space, then filename
          if len(l:rest) >= 3
            let l:file = strpart(l:rest, 2) 
            call add(l:files, l:file)
          endif
        endif
      endfor
      break
    endif
  endfor
  " Go back to original window (optional; this simple version just leaves you where you end)
  return l:files
endfunction


function! s:DoHgCommit() abort
  if get(b:, 'hgcommit_type', '') !=# 'message'
    return
  endif

  " Get selected files
  let l:files = s:GetSelectedHgFiles()
  if empty(l:files)
    echohl ErrorMsg
    echom "No files selected for commit."
    echohl None
    return
  endif

  " Get commit message lines, ignoring leading '#' lines
  let l:all_lines = getline(1, '$')
  let l:msg_lines = []
  for l:L in l:all_lines
    if l:L =~# '^#'
      continue
    endif
    call add(l:msg_lines, l:L)
  endfor

  let l:msg = join(l:msg_lines, "\n")
  if empty(l:msg)
    echohl ErrorMsg
    echom "Commit message is empty."
    echohl None
    return
  endif

  " Write commit message to temp file
  let l:tmpfile = tempname()
  call writefile(l:msg_lines, l:tmpfile)

  " Build command: hg commit -l tmpfile file1 file2 ...
  let l:cmd = 'hg commit -l ' . shellescape(l:tmpfile)
  for l:f in l:files
    let l:cmd .= ' ' . shellescape(l:f)
  endfor

  " Run it
  let l:out = ExecuteCommand(l:cmd)
  let l:status = v:shell_error

  " Clean up temp file
  call delete(l:tmpfile)

  if l:status != 0
    echohl ErrorMsg
    echom "hg commit failed:"
    echom l:out
    echohl None
    return
  endif

  echom "hg commit succeeded."

  " Close only the commit UI buffers in this tab
  try
    for l:w in range(1, winnr('$'))
      execute l:w . 'wincmd w'
      if get(b:, 'hgcommit_type', '') ==# 'filelist'
        bwipeout!
      elseif get(b:, 'hgcommit_type', '') ==# 'message'
        bwipeout!
      endif
    endfor
  catch /^Vim\%((\a\+)\)\=:E/
  endtry
endfunction
