{-# LANGUAGE OverloadedStrings, DeriveFunctor, DeriveFoldable, DeriveTraversable #-}

module HsDev.Database.SQLite.Select (
        Select(..), select_, from_, where_, buildQuery, toQuery,
        qSymbolId, qSymbol, qModuleLocation, qModuleId, qImport, qBuildInfo,
        qNSymbol, qNote
        ) where

import Data.String
import Data.Text (Text)
import qualified Data.Text as T
import Data.Semigroup
import Database.SQLite.Simple
import Text.Format

data Select a = Select {
        selectColumns :: [a],
        selectTables :: [a],
        selectConditions :: [a] }
                deriving (Eq, Ord, Read, Show, Functor, Foldable, Traversable)

instance Semigroup (Select a) where
        Select lc lt lcond <> Select rc rt rcond = Select
                (lc <> rc)
                (lt <> rt)
                (lcond <> rcond)

instance Monoid (Select a) where
        mempty = Select mempty mempty mempty
        mappend l r = l <> r

select_ :: [a] -> Select a
select_ cols = Select cols [] []

from_ :: [a] -> Select a
from_ tbls = Select [] tbls []

where_ :: [a] -> Select a
where_ = Select [] []

buildQuery :: Select Text -> String
buildQuery (Select cols tables conds) = "select {} from {} where {}"
        ~~ T.intercalate ", " cols
        ~~ T.intercalate ", " tables
        ~~ T.intercalate " and " (map (\cond -> T.concat ["(", cond, ")"]) conds)

toQuery :: Select Text -> Query
toQuery = fromString . buildQuery

qSymbolId :: Select Text
qSymbolId = mconcat [
        select_ [
                "s.name",
                "m.name",
                "m.file",
                "m.cabal",
                "m.install_dirs",
                "m.package_name",
                "m.package_version",
                "m.installed_name",
                "m.exposed",
                "m.other_location"],
        from_ ["modules as m", "symbols as s"],
        where_ ["m.id == s.module_id"]]

qSymbol :: Select Text
qSymbol = mconcat [
        qSymbolId,
        select_ [
                "s.docs",
                "s.line",
                "s.column",
                "s.what",
                "s.type",
                "s.parent",
                "s.constructors",
                "s.args",
                "s.context",
                "s.associate",
                "s.pat_type",
                "s.pat_constructor"]]

qModuleLocation :: Text -> Select Text
qModuleLocation ml = template ["ml" ~% ml] [
        select_ [
                "{ml}.file",
                "{ml}.cabal",
                "{ml}.install_dirs",
                "{ml}.package_name",
                "{ml}.package_version",
                "{ml}.installed_name",
                "{ml}.exposed",
                "{ml}.other_location"],
        from_ ["modules as {ml}"]]

qModuleId :: Select Text
qModuleId = mconcat [
        select_ [
                "mu.name",
                "mu.file",
                "mu.cabal",
                "mu.install_dirs",
                "mu.package_name",
                "mu.package_version",
                "mu.installed_name",
                "mu.exposed",
                "mu.other_location"],
        from_ ["modules as mu"],
        where_ ["mu.name is not null"]]

qImport :: Text -> Select Text
qImport i = template ["i" ~% i] [
        select_ [
                "{i}.line", "{i}.column",
                "{i}.module_name",
                "{i}.qualified",
                "{i}.alias"],
        from_ ["imports as {i}"]]

qBuildInfo :: Select Text
qBuildInfo = mconcat [
        select_ [
                "bi.depends",
                "bi.language",
                "bi.extensions",
                "bi.ghc_options",
                "bi.source_dirs",
                "bi.other_modules"],
        from_ ["build_infos as bi"]]

-- | Symbol from haskell-names
qNSymbol :: Text -> Text -> Select Text
qNSymbol m s = template ["m" ~% m, "s" ~% s] [
        select_ [
                "{s}.what",
                "{m}.name",
                "{s}.name",
                "{s}.parent",
                "{s}.constructors",
                "{s}.associate",
                "{s}.pat_type",
                "{s}.pat_constructor"],
        from_ ["symbols as {s}", "modules as {m}"],
        where_ ["{m}.id = {s}.module_id"]]

qNote :: Text -> Text -> Select Text
qNote m n = template ["m" ~% m, "n" ~% n] [
        select_ [
                "{m}.file",
                "{n}.line", "{n}.column", "{n}.line_to", "{n}.column_to",
                "{n}.severity",
                "{n}.message", "{n}.suggestion"],
        from_ ["modules as {m}", "messages as {n}"],
        where_ [
                "{m}.file is not null",
                "{n}.module_id = {m}.id"]]

template :: [FormatArg] -> [Select Text] -> Select Text
template args = fmap ((`formats` args) . T.unpack) . mconcat