content: {-# LANGUAGE OverloadedStrings #-}
  module Main where
  
  import           Data.Maybe
  import           Data.Text                                       (Text)
  import qualified Data.Text                                       as Text
  
  import           Telegram.Bot.API
  import           Telegram.Bot.API.InlineMode.InlineQueryResult
  import           Telegram.Bot.API.InlineMode.InputMessageContent (defaultInputTextMessageContent)
  import           Telegram.Bot.Simple
  import           Telegram.Bot.Simple.UpdateParser                (updateMessageSticker,
                                                                    updateMessageText)
  
  import           Network.Wai.Handler.Warp                        (Port,
                                                                    defaultSettings,
                                                                    setPort)
  import           Network.Wai.Handler.WarpTLS                     (OnInsecure (AllowInsecure),
                                                                    TLSSettings (onInsecure),
                                                                    tlsSettings)
  
  type Model = ()
  
  data Action
    = InlineEcho InlineQueryId Text
    | StickerEcho InputFile ChatId
    | Echo Text
  
  echoBot :: BotApp Model Action
  echoBot = BotApp
    { botInitialModel = ()
    , botAction = updateToAction
    , botHandler = handleAction
    , botJobs = []
    }
  
  updateToAction :: Update -> Model -> Maybe Action
  updateToAction update _
    | isJust $ updateInlineQuery update =  do
        query <- updateInlineQuery update
        let queryId = inlineQueryId query
        let msg =  inlineQueryQuery query
        Just $ InlineEcho queryId msg
    | isJust $ updateMessageSticker update = do
      fileId <- stickerFileId <$> updateMessageSticker update
      chatOfUser <- updateChatId update
      pure $ StickerEcho (InputFileId fileId) chatOfUser
    | otherwise = case updateMessageText update of
        Just text -> Just (Echo text)
        Nothing   -> Nothing
  
  handleAction :: Action -> Model -> Eff Action Model
  handleAction action model = case action of
    InlineEcho queryId msg -> model <# do
      let result = (defInlineQueryResultGeneric (InlineQueryResultId msg))
            { inlineQueryResultTitle = Just msg
            , inlineQueryResultInputMessageContent = Just (defaultInputTextMessageContent msg)
            }
          thumbnail = defInlineQueryResultGenericThumbnail result
          article = defInlineQueryResultArticle thumbnail
          answerInlineQueryRequest = defAnswerInlineQuery queryId [article]
      _ <- runTG answerInlineQueryRequest
      return ()
    StickerEcho file chat -> model <# do
      _ <- runTG
          (defSendSticker (SomeChatId chat) file)
      return ()
    Echo msg -> model <# do
      pure msg -- or replyText msg
  
  run :: Token -> FilePath -> FilePath -> Port -> String -> IO ()
  run token certPath keyPath port ip = do
    env <- defaultTelegramClientEnv token
    res <- startBotWebhook bot config env
    print res
    where
      bot = conversationBot updateChatId echoBot
      tlsOpts = (tlsSettings certPath keyPath) {onInsecure = AllowInsecure}
      warpOpts = setPort port defaultSettings
      certFile = Just $ InputFile certPath "application/x-pem-file"
      url = "https://" ++ ip ++ ":" ++ show port
      config = WebhookConfig
                 { webhookConfigTlsSettings       = tlsOpts,
                   webhookConfigTlsWarpSettings   = warpOpts,
                   webhookConfigSetWebhookRequest = requestData
                 }
      requestData = (defSetWebhook url)
        { setWebhookCertificate    = certFile,
          setWebhookAllowedUpdates = Just ["message"]
        }
  
  main :: IO ()
  main = do
    putStrLn "Please, enter Telegram bot's API token:"
    token <- Token . Text.pack <$> getLine
    putStrLn "Please, enter a path to certificate:"
    cert <- getLine
    putStrLn "Please, enter a path to key:"
    key <- getLine
    putStrLn "Please, enter port(80, 88, 443, 8443):"
    port <- read <$> getLine
    putStrLn "Please, enter ip:"
    ip <- getLine
    run token cert key port ip
  