module Dhall.LSP.Backend.Freezing (
  computeSemanticHash,
  getAllImportsWithHashPositions,
  getImportHashPosition,
  stripHash
) where

import Dhall.Parser (Src(..))
import Dhall.Core (Expr(..), Import(..), ImportHashed(..), subExpressions)

import Control.Lens (universeOf)
import Data.Text (Text)
import qualified Data.Text as Text

import Dhall.LSP.Backend.Dhall (FileIdentifier, Cache, DhallError, typecheck,
  normalize, hashNormalToCode, load)
import Dhall.LSP.Backend.Diagnostics (Range(..), rangeFromDhall,
  positionFromMegaparsec, positionToOffset, subtractPosition)
import Dhall.LSP.Backend.Parsing (getImportHash)

-- | Given an expression (potentially still containing imports) compute its
-- 'semantic' hash in the textual representation used to freeze Dhall imports.
computeSemanticHash :: FileIdentifier -> Expr Src Import -> Cache ->
  IO (Either DhallError (Cache, Text))
computeSemanticHash fileid expr cache = do
  loaded <- load fileid expr cache
  case loaded of
    Left err -> return (Left err)
    Right (cache', expr') -> case typecheck expr' of
      Left err -> return (Left err)
      Right (wt,_) -> do
        return (Right (cache', hashNormalToCode (normalize wt)))

stripHash :: Import -> Import
stripHash (Import (ImportHashed _ importType) mode) =
  Import (ImportHashed Nothing importType) mode

getImportHashPosition :: Src -> Maybe Range
getImportHashPosition src@(Src left _ text)  = do
  Src left' right' _ <- getImportHash src
  let p0 = positionFromMegaparsec left

  -- sanitise the starting point
  let p1 = positionFromMegaparsec left'
      off1 = positionToOffset text (subtractPosition p0 p1)
      Range _ left'' = rangeFromDhall (Src left left' (Text.take off1 text))

  -- sanitise the end point
  let Range _ right'' = rangeFromDhall (Src left right' text)

  return (Range left'' right'')

getAllImportsWithHashPositions :: Expr Src Import -> [(Import, Range)]
getAllImportsWithHashPositions expr =
  [ (i, range) |
    Note src (Embed i) <- universeOf subExpressions expr,
    Just range <- [getImportHashPosition src] ]
