{-# LANGUAGE DeriveGeneric #-}

module Proteome.PersistBuffers(
  loadBuffers,
  storeBuffers,
  PersistBuffers(PersistBuffers),
) where

import GHC.Generics
import Control.Monad (filterM, when)
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Except (runExceptT)
import Data.Aeson (ToJSON(toEncoding), FromJSON, genericToEncoding, defaultOptions)
import Data.Foldable (traverse_)
import System.Directory (doesFileExist)
import System.FilePath ((</>))
import Neovim (vim_get_current_buffer', vim_get_buffers', buffer_get_name', vim_command')
import Ribosome.Api.Buffer (edit, buflisted)
import Ribosome.Persist (persistStore, persistLoad)
import Ribosome.Control.Ribo (lockOrSkip)
import Proteome.Data.Proteome (Proteome)
import Proteome.Data.Project (
  Project(Project),
  ProjectMetadata(DirProject),
  ProjectName(ProjectName),
  ProjectType(ProjectType)
  )
import Proteome.Env (getMainProject)

data PersistBuffers =
  PersistBuffers {
    current :: Maybe FilePath,
    buffers :: [FilePath]
  }
  deriving (Eq, Generic, Show)

instance ToJSON PersistBuffers where
  toEncoding = genericToEncoding defaultOptions

instance FromJSON PersistBuffers

projectSubPath :: Proteome (Maybe FilePath)
projectSubPath = do
  main <- getMainProject
  return $ case main of
    Project (DirProject (ProjectName name) _ (Just (ProjectType tpe))) _ _ _ -> Just $ tpe </> name
    _ -> Nothing

unsafeStoreBuffers :: FilePath -> Proteome ()
unsafeStoreBuffers path = do
  active <- vim_get_current_buffer'
  activeName <- buffer_get_name' active
  activeIsFile <- liftIO $ doesFileExist activeName
  let current' = if activeIsFile then Just activeName else Nothing
  all' <- vim_get_buffers' >>= filterM buflisted >>= traverse buffer_get_name'
  files <- liftIO $ filterM doesFileExist all'
  persistStore (path </> "buffers") (PersistBuffers current' files)

safeStoreBuffers :: FilePath -> Proteome ()
safeStoreBuffers path =
  lockOrSkip "store-buffers" $ unsafeStoreBuffers path

decodePersistBuffers :: FilePath -> Proteome (Either String PersistBuffers)
decodePersistBuffers path = runExceptT $ persistLoad (path </> "buffers")

restoreBuffers :: PersistBuffers -> Proteome ()
restoreBuffers (PersistBuffers current' buffers') = do
  active <- vim_get_current_buffer'
  name <- buffer_get_name' active
  when (null name) $ mapM_ edit current'
  traverse_ (\a -> vim_command' ("silent! badd " ++ a)) buffers'

unsafeLoadBuffers :: FilePath -> Proteome ()
unsafeLoadBuffers path = do
  pb <- decodePersistBuffers path
  mapM_ restoreBuffers pb

safeLoadBuffers :: FilePath -> Proteome ()
safeLoadBuffers path =
  lockOrSkip "load-buffers" $ unsafeLoadBuffers path

storeBuffers :: Proteome ()
storeBuffers = do
  sub <- projectSubPath
  mapM_ safeStoreBuffers sub

loadBuffers :: Proteome ()
loadBuffers = do
  sub <- projectSubPath
  mapM_ safeLoadBuffers sub