{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE OverloadedStrings #-}
module Main
    ( main
    ) where


-------------------------------------------------------------------------------
import           Control.Monad.IO.Class (liftIO)
import           Data.Aeson             (FromJSON (..), defaultOptions,
                                         genericParseJSON, genericToJSON,
                                         object, (.=))
import           Data.List.NonEmpty     (NonEmpty (..))
import           Data.Text              (Text)
import           Data.Time.Calendar     (Day (..))
import           Data.Time.Clock        (UTCTime (..), secondsToDiffTime)
import qualified Data.Vector            as V
import           Database.V5.Bloodhound
import           GHC.Generics           (Generic)
import           Network.HTTP.Client    (defaultManagerSettings)
-------------------------------------------------------------------------------


data TweetMapping = TweetMapping deriving (Eq, Show)

instance ToJSON TweetMapping where
  toJSON TweetMapping =
    object
      [ "properties" .=
        object ["location" .= object ["type" .= ("geo_point" :: Text)]]
      ]
-------------------------------------------------------------------------------
data Tweet = Tweet
  { user     :: Text
  , postDate :: UTCTime
  , message  :: Text
  , age      :: Int
  , location :: LatLon
  } deriving (Eq, Generic, Show)


-------------------------------------------------------------------------------
exampleTweet :: Tweet
exampleTweet =
  Tweet
  { user = "bitemyapp"
  , postDate = UTCTime (ModifiedJulianDay 55000) (secondsToDiffTime 10)
  , message = "Use haskell!"
  , age = 10000
  , location = loc
  }
  where
    loc = LatLon {lat = 40.12, lon = -71.3}

instance ToJSON Tweet where
  toJSON = genericToJSON defaultOptions
instance FromJSON Tweet where
  parseJSON = genericParseJSON defaultOptions


main :: IO ()
main = runBH' $ do
  -- set up index
  _ <- createIndex indexSettings testIndex
  True <- indexExists testIndex
  _ <- putMapping testIndex testMapping TweetMapping

  -- create a tweet
  resp <- indexDocument testIndex testMapping defaultIndexDocumentSettings exampleTweet (DocId "1")
  liftIO (print resp)
  -- Response {responseStatus = Status {statusCode = 201, statusMessage = "Created"}, responseVersion = HTTP/1.1, responseHeaders = [("Content-Type","application/json; charset=UTF-8"),("Content-Length","74")], responseBody = "{\"_index\":\"twitter\",\"_type\":\"tweet\",\"_id\":\"1\",\"_version\":1,\"created\":true}", responseCookieJar = CJ {expose = []}, responseClose' = ResponseClose}

  -- bulk load
  let stream = V.fromList [BulkIndex testIndex testMapping (DocId "2") (toJSON exampleTweet)]
  _ <- bulk stream
  -- Bulk loads require an index refresh before new data is loaded.
  _ <- refreshIndex testIndex

  -- set up some aliases
  let aliasName = IndexName "twitter-alias"
  let iAlias = IndexAlias testIndex (IndexAliasName aliasName)
  let aliasRouting = Nothing
  let aliasFiltering = Nothing
  let aliasCreate = IndexAliasCreate aliasRouting aliasFiltering
  _ <- updateIndexAliases (AddAlias iAlias aliasCreate :| [])
  True <- indexExists aliasName

  -- create a template so that if we just write into an index named tweet-2017-01-02, for instance, the index will be automatically created with the given mapping. This is a great idea for any ongoing indices because it makes them much easier to manage and rotate.
  let idxTpl = IndexTemplate (TemplatePattern "tweet-*") (Just (IndexSettings (ShardCount 1) (ReplicaCount 1))) [toJSON TweetMapping]
  let templateName = TemplateName "tweet-tpl"
  _ <- putTemplate idxTpl templateName
  True <- templateExists templateName

  -- do a search
  let boost = Nothing
  let query = TermQuery (Term "user" "bitemyapp") boost
  let search = mkSearch (Just query) boost
  _ <- searchByType testIndex testMapping search

  -- clean up
  _ <- deleteTemplate templateName
  _ <- deleteIndex testIndex
  False <- indexExists testIndex

  return ()
  where
    testServer = Server "http://localhost:9200"
    runBH' = withBH defaultManagerSettings testServer
    testIndex = IndexName "twitter"
    testMapping = MappingName "tweet"
    indexSettings = IndexSettings (ShardCount 1) (ReplicaCount 0)
