{-# LANGUAGE OverloadedStrings #-}

-- | Generate the cabal info for the given subdirectories, assuming
-- the existence of appropriate "GIR.info" files.

import System.Environment (getArgs)
import System.FilePath ((</>), (<.>))
import System.IO (hPutStrLn, stderr)
import System.Exit (exitFailure)

import Control.Monad (forM_, when)

import qualified Data.Aeson as A
import qualified Data.ByteString as B
import Data.Monoid ((<>))
import qualified Data.Text.Encoding as TE
import qualified Data.Text as T
import Data.Text (Text)

import qualified Data.GI.CodeGen.ProjectInfo as PI
import Data.GI.CodeGen.Util (ucFirst)

import ProjectInfo (ProjectInfo(..))

import qualified Data.ByteString.Lazy as LB

readGIRInfo :: FilePath -> IO ProjectInfo
readGIRInfo fname = do
  buf <- LB.readFile fname
  case A.eitherDecode buf of
    Left err -> error ("Could not parse \"" <> fname <> "\": " <> err)
    Right info -> return info

writeCabal :: FilePath -> ProjectInfo -> IO ()
writeCabal fname info =
    B.writeFile fname $ TE.encodeUtf8 $ T.unlines $
       [ "name:                 " <> name info
       , "version:              " <> version info
       , "synopsis:             " <> synopsis info
       , "description:          " <> description info
       , "homepage:             " <> PI.homepage
       , "license:              " <> PI.license
       , "license-file:         LICENSE"
       , "author:               " <> PI.authors
       , "maintainer:           " <> PI.maintainers
       , "category:             " <> PI.category
       , "build-type:           Custom"
       , "cabal-version:        >= 1.24"
       , let commonFiles = "README.md ChangeLog.md stack.yaml"
         in case girOverrides info of
           Nothing -> "\nextra-source-files: " <> commonFiles <> "\n"
           Just ov -> "\nextra-source-files: " <> commonFiles <> " " <> ov <> "\n"
       , "custom-setup"
       , "      setup-depends: base >= 4.7 && < 5,"
       , "                     Cabal >= 1.24,"
       , "                     haskell-gi >= 0.20.1 && < 1"
       , ""
       , "Flag overloaded-methods"
       , "      Description: Generate support for overloaded methods."
       , ""
       , "Flag overloaded-properties"
       , "      Description: Generate support for overloaded properties."
       , ""
       , "Flag overloaded-signals"
       , "      Description: Generate support for overloaded signals."
       , ""
       , "library"
       , "      default-language: " <> PI.defaultLanguage
       , "      default-extensions: " <> T.intercalate ", " PI.defaultExtensions
       , "      other-extensions: " <> T.intercalate ", " PI.otherExtensions
       , "      ghc-options: " <> T.intercalate " " PI.ghcOptions
       , ""
       , "      pkgconfig-depends: " <> pkgconfigDepends info
       , "      build-depends: " <>
         T.intercalate ",\n                     "
              ([ baseVersion info
               , "haskell-gi-base >= 0.20 && < 1"
                 -- Workaround for https://github.com/commercialhaskell/stack/issues/2094
               , "haskell-gi >= 0.20.1 && < 1" ]
               <> giDepends info <> PI.standardDeps)
       ]

writeSetup :: FilePath -> ProjectInfo -> IO ()
writeSetup fname info =
    B.writeFile fname $ TE.encodeUtf8 $ T.unlines
           [ "{-# LANGUAGE OverloadedStrings #-}"
           , ""
           , "import Data.GI.CodeGen.CabalHooks (setupHaskellGIBinding)"
           , ""
           , "main :: IO ()"
           , "main = setupHaskellGIBinding name version verbose overridesFile outputDir"
           , "  where name = " <> tshow (girName info)
           , "        version = " <> tshow (girVersion info)
           , "        overridesFile = " <> tshow (girOverrides info)
           , "        verbose = False"
           , "        outputDir = Nothing"
           ]
    where tshow :: Show a => a -> Text
          tshow = T.pack . show

writeLicense :: FilePath -> IO ()
writeLicense fname = B.writeFile fname (TE.encodeUtf8 PI.licenseText)

writeStackYaml :: FilePath -> IO ()
writeStackYaml fname =
    B.writeFile fname $ TE.encodeUtf8 $ T.unlines
         [ "packages:"
         , "- '.'"
         , "explicit-setup-deps:"
         , "  ! '*': true"
         , "resolver: nightly-2016-12-05"
         ]

writeReadme :: FilePath -> ProjectInfo -> IO ()
writeReadme fname info =
  let docUrl = "https://hackage.haskell.org/package/" <>
        name info <> "-" <> version info <>
        "/docs/GI-" <> ucFirst (girName info) <> ".html"
  in B.writeFile fname $ TE.encodeUtf8 $ T.unlines
  [ "# Documentation"
  , "Autogenerated documentation for this package can be found at"
  , ""
  , "[" <> docUrl <> "](" <> docUrl <> ")"
  , ""
  , "For general documentation on using [haskell-gi](https://github.com/haskell-gi/haskell-gi) based bindings, see [the project page](https://github.com/haskell-gi/haskell-gi) or [the Wiki](https://github.com/haskell-gi/haskell-gi/wiki)."
  ]

main :: IO ()
main = do
  args <- getArgs

  when (null args) $ do
         hPutStrLn stderr "usage: genBuildInfo [options] dir1 [dir2 [...]]"
         exitFailure

  forM_ args $ \dir -> do
         info <- readGIRInfo (dir </> "pkg.info")
         writeCabal (dir </> T.unpack (name info) <.> "cabal") info
         writeSetup (dir </> "Setup.hs") info
         writeLicense (dir </> "LICENSE")
         writeStackYaml (dir </> "stack.yaml")
         writeReadme (dir </> "README.md") info
