module IHP.IDE.Data.View.Layout
    ( customQuery
    , tableHead
    , renderRows
    , sqlValueToText
    , renderId
    , isBoolField
    , isSqlFunction
    , isSqlFunction_
    , fillField
    , getColDefaultValue
    , renderRowValue
    , renderDefaultWithoutType
    , isBooleanParam
    , headerNav
    ) where

import IHP.ViewPrelude
import IHP.IDE.ToolServer.Types
import IHP.IDE.ToolServer.Routes
import qualified Data.Text as Text
import IHP.IDE.ToolServer.Helper.View

customQuery :: Text -> Html
customQuery :: Text -> Html
customQuery Text
input = [hsx|<div class="p-2 rounded mt-2" style="background-color: #002B36;"><div id="queryInput" style="height:16px">{input}</div></div>|]

tableHead :: [[DynamicField]] -> Text -> Html
tableHead :: [[DynamicField]] -> Text -> Html
tableHead [[DynamicField]]
rows Text
tableName =
    [hsx|
        <thead>
            <tr>
                {forEach (columnNames rows) renderColumnHead}
                <th>
                    <div class="d-flex">
                        <a
                            href={NewRowAction tableName}
                            class="btn btn-link btn-add"
                            data-toggle="tooltip"
                            data-placement="bottom"
                            title={"Add " <> tableNameToModelName tableName}
                        >{addIcon}</a>
                    </div>
                </th>
            </tr>
        </thead>
    |]
    where
        columnNames :: [[model]] -> [b]
columnNames [[model]]
rows = (model -> b) -> [model] -> [b]
forall a b. (a -> b) -> [a] -> [b]
map (Proxy "fieldName" -> model -> b
forall model (name :: Symbol) value.
(KnownSymbol name, HasField name model value) =>
Proxy name -> model -> value
get IsLabel "fieldName" (Proxy "fieldName")
Proxy "fieldName"
#fieldName) ([model] -> Maybe [model] -> [model]
forall a. a -> Maybe a -> a
fromMaybe [] ([[model]] -> Maybe [model]
forall a. [a] -> Maybe a
head [[model]]
rows))
        renderColumnHead :: a -> Html
renderColumnHead a
name = [hsx|<th>{name}</th>|]

renderRows :: [[DynamicField]] -> Html -> Text -> Html
renderRows :: [[DynamicField]] -> Html -> Text -> Html
renderRows [[DynamicField]]
rows Html
body Text
tableName = [hsx|
    <table class="table table-sm table-hover data-rows-table">
        {tableHead rows tableName}
        {body}
    </table>
|]

sqlValueToText :: Maybe ByteString -> Text
sqlValueToText :: Maybe ByteString -> Text
sqlValueToText (Just ByteString
value) = ByteString -> Text
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
value
sqlValueToText Maybe ByteString
Nothing = Text
"NULL"

renderId :: a -> String
renderId a
id = Int -> String -> String
forall a. Int -> [a] -> [a]
take Int
4 (a -> String
forall a b. ConvertibleStrings a b => a -> b
cs a
id) String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String
".." String -> String -> String
forall a. Semigroup a => a -> a -> a
<> String -> String
forall a. [a] -> [a]
reverse (Int -> String -> String
forall a. Int -> [a] -> [a]
take Int
4 (String -> String
forall a. [a] -> [a]
reverse (a -> String
forall a b. ConvertibleStrings a b => a -> b
cs a
id)))

isBoolField :: a -> t model -> Bool
isBoolField a
fieldName t model
tableCols = case ((model -> Bool) -> t model -> Maybe model
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
find (\model
c -> Proxy "columnName" -> model -> a
forall model (name :: Symbol) value.
(KnownSymbol name, HasField name model value) =>
Proxy name -> model -> value
get IsLabel "columnName" (Proxy "columnName")
Proxy "columnName"
#columnName model
c a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== (a -> a
forall a b. ConvertibleStrings a b => a -> b
cs a
fieldName)) t model
tableCols) of
    Just model
columnDef -> (Proxy "columnType" -> model -> a
forall model (name :: Symbol) value.
(KnownSymbol name, HasField name model value) =>
Proxy name -> model -> value
get IsLabel "columnType" (Proxy "columnType")
Proxy "columnType"
#columnType model
columnDef) a -> a -> Bool
forall a. Eq a => a -> a -> Bool
== a
"boolean"
    Maybe model
Nothing -> Bool
False

isSqlFunction :: Text -> Bool
isSqlFunction :: Text -> Bool
isSqlFunction Text
text = Text
text Text -> [Text] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem`
    [ Text
"uuid_generate_v4()"
    , Text
"NOW()"
    , Text
"NULL"]

isSqlFunction_ :: ByteString -> Bool
isSqlFunction_ :: ByteString -> Bool
isSqlFunction_ ByteString
text = ByteString
text ByteString -> [ByteString] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem`
    [ ByteString
"uuid_generate_v4()"
    , ByteString
"NOW()"
    , ByteString
"NULL"]

fillField :: model -> a -> a -> a
fillField model
col a
value a
isBoolField = a
"fillField('" a -> a -> a
forall a. Semigroup a => a -> a -> a
<> Proxy "columnName" -> model -> a
forall model (name :: Symbol) value.
(KnownSymbol name, HasField name model value) =>
Proxy name -> model -> value
get IsLabel "columnName" (Proxy "columnName")
Proxy "columnName"
#columnName model
col a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
"', '" a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
value a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
"'," a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
isBoolField a -> a -> a
forall a. Semigroup a => a -> a -> a
<> a
");"

getColDefaultValue :: ColumnDefinition -> Text
getColDefaultValue :: ColumnDefinition -> Text
getColDefaultValue ColumnDefinition { Maybe Text
$sel:columnDefault:ColumnDefinition :: ColumnDefinition -> Maybe Text
columnDefault :: Maybe Text
columnDefault, Bool
$sel:isNullable:ColumnDefinition :: ColumnDefinition -> Bool
isNullable :: Bool
isNullable } = case Maybe Text
columnDefault of
        Just Text
value -> Text
value
        Maybe Text
Nothing -> if Bool
isNullable
            then Text
"NULL"
            else Text
""

renderRowValue :: Maybe ByteString -> Text
renderRowValue :: Maybe ByteString -> Text
renderRowValue (Just ByteString
value) = Text
"'" Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> ByteString -> Text
forall a b. ConvertibleStrings a b => a -> b
cs ByteString
value Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"'"
renderRowValue Maybe ByteString
Nothing = Text
"NULL"

renderDefaultWithoutType :: Text -> Text
renderDefaultWithoutType :: Text -> Text
renderDefaultWithoutType Text
"" = Text
""
renderDefaultWithoutType Text
input = case [Text] -> Int
forall (t :: * -> *) a. Foldable t => t a -> Int
length (Text -> Text -> [Text]
Text.splitOn Text
"'" Text
input) of
        Int
3 -> (Text -> Text -> [Text]
Text.splitOn Text
"'" Text
input) [Text] -> Int -> Text
forall a. [a] -> Int -> a
!! Int
1
        Int
_ -> Text
input

isBooleanParam :: Bool -> ColumnDefinition -> Html
isBooleanParam :: Bool -> ColumnDefinition -> Html
isBooleanParam Bool
isBool ColumnDefinition
def = [hsx|
<input
    type="hidden"
    name={get #columnName def <> "-isBoolean"}
    value={inputValue isBool}
    />
|]


headerNav :: Html
headerNav :: Html
headerNav = [hsx|
    <div class="view-selector">
        <div class="container-fluid">
            <a href={ShowDatabaseAction} class={classes [("active", databaseActive)]}>
                Database
            </a>

            <a href={NewQueryAction} class={classes [("active", sqlActive)]}>
                SQL
            </a>
        </div>
    </div>
|]
    where
        databaseActive :: Bool
        databaseActive :: Bool
databaseActive = (?context::ControllerContext, Typeable DataController) => Bool
forall controller.
(?context::ControllerContext, Typeable controller) =>
Bool
isActiveController @DataController Bool -> Bool -> Bool
&& Bool -> Bool
not Bool
sqlActive

        sqlActive :: Bool
        sqlActive :: Bool
sqlActive = DataController -> Bool
forall controller.
(?context::ControllerContext, PathString controller) =>
controller -> Bool
isActivePath DataController
NewQueryAction Bool -> Bool -> Bool
|| DataController -> Bool
forall controller.
(?context::ControllerContext, PathString controller) =>
controller -> Bool
isActivePath DataController
QueryAction