{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE TypeFamilies #-}
-- | Module for interfacing <http://cmd.fm>
module Web.Radio.Cmd where

import qualified Control.Exception as E
import           Control.Monad (liftM)
import           Data.Aeson
import qualified Data.ByteString.Char8 as C
import           Data.Conduit (($$+-))
import           Data.Conduit.Attoparsec (sinkParser)
import qualified Data.HashMap.Strict as HM
import           GHC.Generics (Generic)
import           Network.HTTP.Conduit
import           Network.HTTP.Types (renderQuery)
import           Network.HTTP.Types.Header (hLocation)
import           Network.HTTP.Types.Status (status302)

import qualified Web.Radio as Radio


data Cmd = Cmd
    { sc_id :: Int
    , title :: String
    , artwork_url :: String
    , description   :: String
    , duration      :: Int
    --, genre         :: String
    , tag_list      :: String
    , waveform_url  :: String
    , stream_url    :: String
    --, last_listened :: Int
    , main_type     :: String
    --, created_at    :: String
    --, updated_at    :: String
    } deriving (Show, Generic)

instance FromJSON Cmd

instance Radio.Radio Cmd where
    data Param Cmd = Genre String

    parsePlaylist val =
        case fromJSON val of
            Success s -> s
            Error err -> error $ "Parse playlist failed: " ++ show err

    getPlaylist (Genre g) = do
        let url = "http://cmd.fm/api/tracks/search"
            query = [ ("genre", Just $ C.pack g)
                    , ("limit", Just $ C.pack "10") ]
        initReq <- parseUrl url
        let req = initReq { method = "GET"
                          , queryString = renderQuery False query
                          }
        withManager $ \manager -> do
            res <- http req manager
            liftM Radio.parsePlaylist (responseBody res $$+- sinkParser json)

    songUrl _ x = do
        initReq <- parseUrl url
        let req = initReq { method = "GET"
                          , queryString = renderQuery False query
                          }
        E.catch (withManager $ \manager ->
                    httpLbs req { redirectCount = 0 } manager >> return "")
                (\e -> case e of
                    (StatusCodeException s hdr _) ->
                        if s == status302 then redirect hdr
                        else return ""
                    otherException -> print otherException >> return ""
                )
      where
        url = stream_url x
        query = [("client_id", Just $ C.pack "2b659ea66970555922d89ce9c07b2d0d")]
        redirect hdr = case HM.lookup hLocation $ HM.fromList hdr of
                            Just u   -> return $ C.unpack u
                            Nothing  -> return ""

    songMeta x = Radio.SongMeta "" "" (title x)

    tagged _ = False

-- Currently, no api is provided to retrieve genre list.
genres :: IO [String]
genres = return
    ["80s","Abstract","Acid Jazz","Acoustic"
    ,"Acoustic Rock","Alternative","Ambient","Avantgarde"
    ,"Ballads","Blues","Blues Rock","Breakbeats"
    ,"Chillout","Chiptunes","Choir","Classic Rock"
    ,"Classical","Classical Guitar","Contemporary","Dance"
    ,"Dancehall","Death Metal","Dirty South","Disco"
    ,"Dream Pop","Drum & Bass","Dub","Dubstep"
    ,"Easy Listening","Electro House","Electronic","Electronic Pop"
    ,"Electronic Rock","Folk Rock","Funk","Glitch"
    ,"Grime","Grindcore","Grunge","Hard Rock",
    "Hardcore","Heavy Metal","Hip-Hop","House"
    ,"Indie","Indie Pop","Industrial Metal","Instrumental"
    ,"Instrumental Rock","J-Pop","Jazz","Jazz Funk"
    ,"Jazz Fusion","K-Pop","Latin Jazz","Metalcore"
    ,"Minimal","Modern Jazz","Moombahton","New Wave"
    ,"Nu Jazz","Opera","Orchestral","Piano"
    ,"Pop","Post Hardcore","Post Rock","Progressive House"
    ,"Progressive Metal","Progressive Rock","Punk"
    ,"R&B","Rap","Reggae","Reggaeton","Riddim"
    ,"Rock","Rock 'n' Roll","Shoegaze","Singer / Songwriter"
    ,"Smooth Jazz","Soul","Synth Pop","Tech House"
    ,"Techno","Thrash Metal","Trance","Trap"
    ,"Trip-hop","Turntablism","Underground"]

pprGenres :: [String] -> IO ()
pprGenres [] = return ()
pprGenres gs = do
    putStrLn $ foldr1 f (take 4 gs)
    pprGenres $ drop 4 gs
  where
    f a b = a ++ concat (replicate (20 - length a) " ") ++ b