import qualified Codec.Archive.Tar as Tar
import qualified Codec.Compression.GZip as GZ
import           Control.Monad (forM_, when)
import           Data.ByteString (ByteString)
import qualified Data.ByteString.Lazy as BL
import           Data.Char (toLower)
import qualified Data.Text.Lazy.IO as TL
import           Distribution.Compiler (CompilerId(..), CompilerFlavor(..))
import           Distribution.Homebrew
import qualified Distribution.PackageDescription as PD
import           Distribution.PackageDescription.Configuration (finalizePackageDescription)
import           Distribution.PackageDescription.Parse (readPackageDescription)
import           Distribution.System (Platform(..), Arch(..), OS(..))
import           Distribution.Verbosity (silent)
import           Distribution.Version (Version(..))
import           Network.HTTP (simpleHTTP, defaultGETRequest_, getResponseBody)
import           Network.URI (URI(..), parseURI)
import           Prelude hiding (or)
import           System.Directory
import           System.FilePath ((</>),(<.>))
import           Text.Printf (printf)


-- * Configuration

instantiatePackageDescription :: PD.GenericPackageDescription -> Maybe PD.PackageDescription
instantiatePackageDescription gpd = case finalize gpd of
  Left       _  -> Nothing
  Right (pd, _) -> Just pd
  where
    flags    = []
    isokay   = const True
    platform = Platform I386 OSX
    compiler = CompilerId GHC (Version [7,6,3] [])
    miscDeps = []
    finalize = finalizePackageDescription flags isokay platform compiler miscDeps

remoteIndex :: String
remoteIndex = "http://hackage.haskell.org/packages/index.tar.gz"

localIndex :: FilePath
localIndex = "index"


-- * Main script

main :: IO ()
main = do

  --home <- getHomeDirectory
  --let cache =
  --      home </> "Library" </> "Haskell" </> "repo-cache" </> "hackage.haskell.org"

  putStrLn "Downloading the latest package list from hackage.haskell.org"
  case parseURI remoteIndex of
    Nothing  -> error $ "Invalid URI: " ++ remoteIndex
    Just uri -> do
      indexTarGz <- getRequest uri
      let indexTar = GZ.decompress (BL.fromChunks ((:[]) indexTarGz))
      BL.writeFile "index.tar" indexTar
      createDirectoryIfMissing False localIndex
      Tar.extract localIndex "index.tar"
      removeFile "index.tar"

      putStrLn "Analysing package list"
      packages <- getDirectoryContents localIndex
      forM_ packages $ \package -> do

        let packagePath   = localIndex </> package
        packagePathExists <- doesDirectoryExist packagePath
        when (packagePathExists && package `notElem` [".",".."]) $ do

          versions <- getDirectoryContents packagePath
          let latestVersion = maximum versions
          let latestPath    = packagePath </> latestVersion
          let cabalFile     = latestPath </> package <.> "cabal"
          cabalFileExists   <- doesFileExist cabalFile
          when cabalFileExists $ do

            gpd <- readPackageDescription silent cabalFile
            case instantiatePackageDescription gpd of
              Nothing -> return ()
              Just pd -> do

                maybeFormula <- fromPackageDescription pd
                case maybeFormula of
                 Nothing       -> return ()
                 Just formDesc -> do

                   formCode <- renderFormula formDesc
                   let formPath = map toLower package <.> "rb"

                   putStrLn (printf "Writing formula for %s-%s" package latestVersion)
                   TL.writeFile formPath formCode

      removeDirectoryRecursive localIndex
      putStrLn "Done"


getRequest :: URI -> IO ByteString
getRequest url = simpleHTTP (defaultGETRequest_ url) >>= getResponseBody
