{-# LANGUAGE DeriveGeneric       #-}
{-# LANGUAGE ScopedTypeVariables #-}
-- runghc -package-env=default Validate.hs validate.yml.zinza .github/workflows/validate.yml
module Main (main) where

import Data.List          (isPrefixOf)
import Data.Maybe         (fromMaybe)
import GHC.Generics       (Generic)
import System.Environment (getArgs)
import System.Exit        (exitFailure)
import Zinza              (Zinza (..), genericFromValueSFP, genericToTypeSFP, genericToValueSFP, parseAndCompileTemplateIO)

import qualified Data.ByteString.Lazy.Char8 as LBS8
import qualified Data.YAML                  as YAML

main :: IO ()
main = do
    args <- getArgs
    case args of
        [src,tgt] -> do
            run <- parseAndCompileTemplateIO src
            -- this shouldn't fail (run-time errors are due bugs in zinza)
            w <- run Z
                { zJobs =
                    [ GhcJob "9.0.1"  False "--lib-only"                False ["8.8.4"] libSteps
                    , GhcJob "8.10.4" False ""                          False ["8.8.4"] defSteps
                    , GhcJob "8.8.4"  False "--solver-benchmarks"       False []        defSteps
                    , GhcJob "8.6.5"  False "--complete-hackage-tests"  False ["8.8.4"] defSteps
                    , GhcJob "8.4.4"  False ""                          False ["8.8.4"] defSteps
                    , GhcJob "8.2.2"  False ""                          False ["8.8.4"] defSteps
                    , GhcJob "8.0.2"  False ""                          False ["8.8.4"] defSteps
                    , GhcJob "7.10.3" False ""                          False ["8.8.4"] defSteps
                    , GhcJob "7.8.4"  False "--lib-only"                False ["8.8.4"] libSteps
                    , GhcJob "7.6.3"  True  "--lib-only"                False ["8.8.4"] libSteps
                    , GhcJob "8.8.4"  True  "--lib-only"                True  ["8.8.4"] $
                        libSteps ++
                        [ "lib-suite-extras --extra-hc /opt/ghc/7.0.4/bin/ghc-7.0.4"
                        , "lib-suite-extras --extra-hc /opt/ghc/7.2.2/bin/ghc-7.2.2"
                        , "lib-suite-extras --extra-hc /opt/ghc/7.4.2/bin/ghc-7.4.2"
                        ]
                    ]
                , zMacosJobs =
                    [ mkMacGhcJob "8.8.4" "https://downloads.haskell.org/~ghc/8.8.4/ghc-8.8.4-x86_64-apple-darwin.tar.xz"
                    , mkMacGhcJob "8.6.5" "https://downloads.haskell.org/~ghc/8.6.5/ghc-8.6.5-x86_64-apple-darwin.tar.xz"
                    ]
                , zWinJobs =
                    [ mkWinGhcJob "8.6.5"  Nothing           []
                    , mkWinGhcJob "8.10.4" (Just "8.10.4")   []
                    ]
                , zMangleVersion = map mangleChar
                , zOr            = (||)
                , zNotNull       = not . null
                , zFalse         = False
                }

            -- check that YAML is syntactically valid
            let bs = LBS8.pack w
            case YAML.decode1 bs of
                Right (_ :: YAML.Node YAML.Pos) -> return ()
                Left (pos, err)                 -> do
                    putStrLn $ "ERROR:" ++ YAML.prettyPosWithSource pos bs err
                    exitFailure

            writeFile tgt w
        _ -> putStrLn "Usage source.yml.zinza target.yml"

mangleChar :: Char -> Char
mangleChar '.' = '_'
mangleChar c   = c

defSteps :: [String]
defSteps =
    [ "print-config"
    , "print-tool-versions"
    , "make-cabal-install-dev"
    , "build"
    , "lib-tests"
    , "lib-suite"
    , "cli-tests"
    , "cli-suite"
    ]

libSteps :: [String]
libSteps =
    [ "print-config"
    , "print-tool-versions"
    , "build"
    , "lib-tests"
    , "lib-suite"
    ]

data Z = Z
    { zJobs          :: [GhcJob]
    , zMacosJobs     :: [MacGhcJob]
    , zWinJobs       :: [WinGhcJob]
    , zMangleVersion :: String -> String
    , zOr            :: Bool -> Bool -> Bool
    , zNotNull       :: [String] -> Bool
    , zFalse         :: Bool
    }
  deriving (Generic)

data GhcJob = GhcJob
    { gjVersion :: String
    , gjXenial  :: Bool
    , gjFlags   :: String
    , gjOld     :: Bool
    , gjNeeds   :: [String]
    , gjSteps   :: [String]
    }
  deriving (Generic)

data MacGhcJob = MacGhcJob
    { mgjVersion :: String
    , mgjGhcUrl  :: String
    , mgjFlags   :: String
    , mgjNeeds   :: [String]
    , mgjSteps   :: [String]
    }
  deriving (Generic)

mkMacGhcJob :: String -> String -> MacGhcJob
mkMacGhcJob v u = MacGhcJob
    { mgjVersion = v
    , mgjGhcUrl  = u
    , mgjFlags   = ""
    , mgjNeeds   = ["8.8.4" | not $ "8.8" `isPrefixOf` v ]
    , mgjSteps   = defSteps
    }

data WinGhcJob = WinGhcJob
    { wgjVersion      :: String
    , wgjChocoVersion :: String
    , wgjNeeds        :: [String]
    }
  deriving (Generic)

mkWinGhcJob :: String -> Maybe String -> [String] -> WinGhcJob
mkWinGhcJob v mv = WinGhcJob v (fromMaybe v mv)

instance Zinza Z where
    toType    = genericToTypeSFP
    toValue   = genericToValueSFP
    fromValue = genericFromValueSFP

instance Zinza GhcJob where
    toType    = genericToTypeSFP
    toValue   = genericToValueSFP
    fromValue = genericFromValueSFP

instance Zinza MacGhcJob where
    toType    = genericToTypeSFP
    toValue   = genericToValueSFP
    fromValue = genericFromValueSFP

instance Zinza WinGhcJob where
    toType    = genericToTypeSFP
    toValue   = genericToValueSFP
    fromValue = genericFromValueSFP
