module JavaScript.Web.Storage
    ( localStorage
    , sessionStorage
    , Storage
    , getLength
    , getIndex
    , getItem
    , setItem
    , removeItem
    , clear
    ) where

import Data.Map.Strict (Map)
import qualified Data.Map.Strict as M
import Data.IORef (IORef, modifyIORef, newIORef, readIORef, writeIORef)
import Data.JSString
import System.IO.Unsafe (unsafePerformIO)

newtype Storage = Storage (IORef (Map JSString JSString))

localStorage :: Storage
localStorage = Storage . unsafePerformIO $ newIORef mempty
{-# NOINLINE localStorage #-}

sessionStorage :: Storage
sessionStorage = Storage . unsafePerformIO $ newIORef mempty
{-# NOINLINE sessionStorage #-}

getLength :: Storage -> IO Int
getLength (Storage s) = M.size <$> readIORef s

getIndex :: Int -> Storage -> IO (Maybe JSString)
getIndex i (Storage s) = do
    m <- readIORef s
    if i >= 0 && i < M.size m
        then pure $ Just $ fst $ M.elemAt i m
        else pure Nothing

getItem :: JSString -> Storage -> IO (Maybe JSString)
getItem key (Storage s) = M.lookup key <$> readIORef s

setItem :: JSString -> JSString -> Storage -> IO ()
setItem key val (Storage s) = modifyIORef s $ M.insert key val

removeItem :: JSString -> Storage -> IO ()
removeItem key (Storage s) = modifyIORef s $ M.delete key

clear :: Storage -> IO ()
clear (Storage s) = writeIORef s mempty