{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE OverloadedStrings #-}

module Hack2.Contrib.Request where

import Data.ByteString.Char8 (ByteString)
import Data.Maybe
import Hack2 hiding (body)
import Hack2.Contrib.Constants
import Hack2.Contrib.Utils
import Air.Env hiding (Default, def)
import Prelude ()
import qualified Data.ByteString.Char8 as B
import Hack2.Contrib.AirBackports
import Data.List (all)
import Data.Char (isSpace)
import Data.Text (Text, splitOn)
import qualified Data.Text as T
import Data.Text.Encoding (decodeUtf8, encodeUtf8)
import Network.URI (unEscapeString)


input_bytestring :: Env -> IO ByteString
input_bytestring = hack_input > return

scheme :: Env -> ByteString
scheme = hack_url_scheme > show > lower > B.pack

port :: Env -> Int
port = server_port

path :: Env -> ByteString
path env = env.script_name + env.path_info

content_type :: Env -> ByteString
content_type env = env.httpHeaders.get _ContentType .fromMaybe ""

{-
media_type :: Env -> ByteString
media_type env = case env.content_type.B.unpack.split "\\s*[;,]\\s*" of
  [] -> ""
  x:_ -> x.lower.B.pack



media_type_params :: Env -> [(ByteString, ByteString)]
media_type_params env
  | env.content_type.B.unpack.empty = []
  | otherwise =
      env
        .content_type
        .B.unpack
        .split "\\s*[;,]\\s"
        .drop 1
        .map (split "=")
        .select (length > is 2)
        .map tuple2
        .map_fst (lower > B.pack)
        .map_snd (B.pack)


content_charset :: Env -> ByteString
content_charset env = env.media_type_params.lookup "charset" .fromMaybe ""
-}

host :: Env -> ByteString
host env = env.httpHeaders.get _Host .fromMaybe (env.server_name) .as_string (takeWhile (is_not ':'))


params :: Env -> [(ByteString, ByteString)]
params env =
  if env.query_string.B.unpack.all isSpace
    then []
    else env.query_string.decodeUtf8.decode_params.map_both (T.unpack > unEscapeString > u2b > B.pack)
  where
    decode_params :: Text -> [(Text, Text)]
    decode_params x =
      x.splitOn "&".map decode_pair

    decode_pair :: Text -> (Text, Text)
    decode_pair x =
      case x.splitOn "=" of
        [] -> ("", "")
        [x] -> (x, "")
        (x:y:_) -> (x,y)

-- inputs :: Env -> IO [(ByteString, ByteString)]
-- inputs env = do
--   _body <- env.input_bytestring
--   return -
--     env
--       .httpHeaders
--       .map_fst (B.unpack > upper > map (\x -> if x == '-' then '_' else x)) -- cgi env use all cap letters
--       .map_snd B.unpack
--       .(("REQUEST_METHOD", env.request_method.show) : ) -- for cgi request
--       .flip decodeInput (_body.s2l)
--       .fst
--       .concatMap to_headers
--
--   where
--     to_headers (k, input) = case input.inputFilename of
--       Nothing -> [(k.B.pack, input.inputValue.l2s)]
--       Just name ->
--         [  (k.B.pack, input.inputValue.l2s)
--         ,  ("hack2_input_file_name_" + k.B.pack, name.B.pack)
--         ]

referer :: Env -> ByteString
referer = httpHeaders > get _Referer > fromMaybe "/"

-- cookies :: Env -> [(ByteString, ByteString)]
-- cookies env = case env.httpHeaders.get _Cookie of
--   Nothing -> []
--   Just s -> s.B.unpack.readCookies .map_both B.pack

fullpath :: Env -> ByteString
fullpath env =
  if env.query_string.B.unpack.all isSpace
    then env.path
    else env.path + "?" + env.query_string

set_http_header :: ByteString -> ByteString -> Env -> Env
set_http_header k v env = env {httpHeaders = env.httpHeaders.put k v}

set_hack_header :: ByteString -> ByteString -> Env -> Env
set_hack_header k v env = env {hackHeaders = env.hackHeaders.put k v}

url :: Env -> ByteString
url env =
  [  env.scheme
  ,  "://"
  ,  env.host
  ,  port_string
  ,  env.fullpath
  ]
  .B.concat
  where
    port_string =
      if (env.scheme.is "https" && env.port.is_not 443 ||
          env.scheme.is "http" && env.port.is_not 80 )
        then ":" + env.server_port.show_bytestring
        else ""


remote_host :: Env -> ByteString
remote_host env =
  ( env.hackHeaders + env.httpHeaders ) .lookup "RemoteHost" .fromMaybe ""