sync' :: Manager -> AccessToken -> ResourceT IO ()
sync' manager token = do
    liftIO $ infoM "Sync.sync" "Start sync"
    (syncDir, syncFile, previousState, localFiles) <- liftIO initLocalState
    (root, _, mbox) <- getAccount manager token
    flip runReaderT (manager, token, DP.csrfToken root, mbox) $ do
        liftIO $ debugM "Sync.sync" "before getRemoteState"
        remoteState <- getRemoteState
        liftIO $ debugM "Sync.sync" "afterGetRemoteState"
        let remoteFiles = getFileSetFromMap remoteState
        let previousRemoteFiles = remoteSyncState previousState
        let previousLocalFiles = localSyncState previousState
        let localChanges = computeChanges localFiles previousLocalFiles
        let remoteChanges = computeChanges remoteFiles previousRemoteFiles
        --server always win if conflict TODO: better handle conflicts
        let changesToApplyLocal = remoteChanges
        let changesToApplyRemote = computeChangesToApply localChanges remoteChanges
        liftIO $ infoM "Sync.sync" ("localChanges:\n" ++ formatList localChanges)
        liftIO $ infoM "Sync.sync" ("remoteChanges:\n" ++ formatList remoteChanges)
        appliedLocalChanges <- applyChangesLocal syncDir remoteState changesToApplyLocal
        appliedRemoteChanges <- applyChangesRemote syncDir remoteState changesToApplyRemote
        liftIO $ debugM "Sync.sync" "finished applying changes"
        let newLocalState = computeNewState previousLocalFiles localChanges appliedLocalChanges appliedRemoteChanges
        let newRemoteState = computeNewState previousRemoteFiles remoteChanges appliedRemoteChanges appliedLocalChanges
        liftIO $ debugM "Sync.sync" "computed new state"
        liftIO $ writeSyncState syncFile (SyncState newLocalState newRemoteState)
        liftIO $ debugM "Sync.sync" "wrote new state to file"
        return ()
sync' :: Manager -> AccessToken -> ResourceT IO ()
sync' manager token = do
    liftIO $ infoM "Sync.sync" "Start sync"
    (syncDir, syncFile, previousState, localFiles) <- liftIO initLocalState
    (root, _, mbox) <- getAccount manager token
    flip runReaderT (manager, token, DP.csrfToken root, mbox) $ do
        liftIO $ debugM "Sync.sync" "before getRemoteState"
        remoteState <- getRemoteState
        liftIO $ debugM "Sync.sync" "afterGetRemoteState"
        let remoteFiles = getFileSetFromMap remoteState
        let previousRemoteFiles = remoteSyncState previousState
        let previousLocalFiles = localSyncState previousState
        let localChanges = computeChanges localFiles previousLocalFiles
        let remoteChanges = computeChanges remoteFiles previousRemoteFiles
        --server always win if conflict TODO: better handle conflicts
        let changesToApplyLocal = remoteChanges
        let changesToApplyRemote = computeChangesToApply localChanges remoteChanges
        liftIO $ infoM "Sync.sync" ("localChanges:\n" ++ formatList localChanges)
        liftIO $ infoM "Sync.sync" ("remoteChanges:\n" ++ formatList remoteChanges)
        appliedLocalChanges <- applyChangesLocal syncDir remoteState changesToApplyLocal
        appliedRemoteChanges <- applyChangesRemote syncDir remoteState changesToApplyRemote
        liftIO $ debugM "Sync.sync" "finished applying changes"
        let newLocalState = computeNewState previousLocalFiles localChanges appliedLocalChanges appliedRemoteChanges
        let newRemoteState = computeNewState previousRemoteFiles remoteChanges appliedRemoteChanges appliedLocalChanges
        liftIO $ debugM "Sync.sync" "computed new state"
        liftIO $ writeSyncState syncFile (SyncState newLocalState newRemoteState)
        liftIO $ debugM "Sync.sync" "wrote new state to file"
        return ()
sync' manager token = do
    liftIO $ infoM "Sync.sync" "Start sync"
    (syncDir, syncFile, previousState, localFiles) <- liftIO initLocalState
    (root, _, mbox) <- getAccount manager token
    flip runReaderT (manager, token, DP.csrfToken root, mbox) $ do
        liftIO $ debugM "Sync.sync" "before getRemoteState"
        remoteState <- getRemoteState
        liftIO $ debugM "Sync.sync" "afterGetRemoteState"
        let remoteFiles = getFileSetFromMap remoteState
        let previousRemoteFiles = remoteSyncState previousState
        let previousLocalFiles = localSyncState previousState
        let localChanges = computeChanges localFiles previousLocalFiles
        let remoteChanges = computeChanges remoteFiles previousRemoteFiles
        --server always win if conflict TODO: better handle conflicts
        let changesToApplyLocal = remoteChanges
        let changesToApplyRemote = computeChangesToApply localChanges remoteChanges
        liftIO $ infoM "Sync.sync" ("localChanges:\n" ++ formatList localChanges)
        liftIO $ infoM "Sync.sync" ("remoteChanges:\n" ++ formatList remoteChanges)
        appliedLocalChanges <- applyChangesLocal syncDir remoteState changesToApplyLocal
        appliedRemoteChanges <- applyChangesRemote syncDir remoteState changesToApplyRemote
        liftIO $ debugM "Sync.sync" "finished applying changes"
        let newLocalState = computeNewState previousLocalFiles localChanges appliedLocalChanges appliedRemoteChanges
        let newRemoteState = computeNewState previousRemoteFiles remoteChanges appliedRemoteChanges appliedLocalChanges
        liftIO $ debugM "Sync.sync" "computed new state"
        liftIO $ writeSyncState syncFile (SyncState newLocalState newRemoteState)
        liftIO $ debugM "Sync.sync" "wrote new state to file"
        return ()