    {-# LANGUAGE OverloadedStrings, FlexibleContexts #-}

    module Network.Protocol.MusicBrainz.JSON.WebService (
        getRecordingById
      , getReleaseById
      , searchReleasesByArtistAndRelease
    ) where

    import Network.Protocol.MusicBrainz.Types

    import Control.Monad.IO.Class (MonadIO)
    import Data.Aeson (eitherDecode)
    import qualified Data.ByteString.Lazy as BL
    import Data.List (intercalate)
    import Data.Text (Text)
    import qualified Data.Text as T
    import Network.HTTP.Base (urlEncode)
    import Network.HTTP.Conduit (simpleHttp)

    musicBrainzWSLookup :: MonadIO m => Text -> Text -> [Text] -> m BL.ByteString
    musicBrainzWSLookup :: forall (m :: * -> *).
    MonadIO m =>
    Text -> Text -> [Text] -> m ByteString
    musicBrainzWSLookup Text
    reqtype Text
    param [Text]
    incparams = do
        let url :: [Char]
    url = [Char]
    "https://musicbrainz.org/ws/2/" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Text -> [Char]
    T.unpack Text
    reqtype [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    "/" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Text -> [Char]
    T.unpack Text
    param [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Text] -> [Char]
    incs [Text]
    incparams [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    fj
        [Char] -> m ByteString
    forall (m :: * -> *). MonadIO m => [Char] -> m ByteString
    simpleHttp [Char]
    url
        where
            incs :: [Text] -> [Char]
    incs [] = [Char]
    ""
            incs [Text]
    xs = ([Char]
    "?inc="[Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++) ([Char] -> [Char]) -> ([Text] -> [Char]) -> [Text] -> [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . [Char] -> [[Char]] -> [Char]
    forall a. [a] -> [[a]] -> [a]
    intercalate [Char]
    "+" ([[Char]] -> [Char]) -> ([Text] -> [[Char]]) -> [Text] -> [Char]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Text -> [Char]) -> [Text] -> [[Char]]
    forall a b. (a -> b) -> [a] -> [b]
    map Text -> [Char]
    T.unpack ([Text] -> [Char]) -> [Text] -> [Char]
    forall a b. (a -> b) -> a -> b
    $ [Text]
    xs
            fj :: [Char]
    fj = [Char]
    "&fmt=json"

    musicBrainzWSSearch :: MonadIO m => Text -> Text -> Maybe Int -> Maybe Int -> m BL.ByteString
    musicBrainzWSSearch :: forall (m :: * -> *).
    MonadIO m =>
    Text -> Text -> Maybe Int -> Maybe Int -> m ByteString
    musicBrainzWSSearch Text
    reqtype Text
    query Maybe Int
    mlimit Maybe Int
    moffset = do
        let url :: [Char]
    url = [Char]
    "https://musicbrainz.org/ws/2/" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Text -> [Char]
    T.unpack Text
    reqtype [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    "/?query=" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char] -> [Char]
    urlEncode (Text -> [Char]
    T.unpack Text
    query) [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Maybe Int -> [Char]
    forall {a}. Show a => Maybe a -> [Char]
    limit Maybe Int
    mlimit [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Maybe Int -> [Char]
    forall {a}. Show a => Maybe a -> [Char]
    offset Maybe Int
    moffset [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    fj
        [Char] -> m ByteString
    forall (m :: * -> *). MonadIO m => [Char] -> m ByteString
    simpleHttp [Char]
    url
        where
            limit :: Maybe a -> [Char]
    limit Maybe a
    Nothing = [Char]
    ""
            limit (Just a
    l) = [Char]
    "&limit=" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ a -> [Char]
    forall a. Show a => a -> [Char]
    show a
    l
            offset :: Maybe a -> [Char]
    offset Maybe a
    Nothing = [Char]
    ""
            offset (Just a
    o) = [Char]
    "&offset=" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ a -> [Char]
    forall a. Show a => a -> [Char]
    show a
    o
            fj :: [Char]
    fj = [Char]
    "&fmt=json"

    getRecordingById :: MonadIO m => MBID -> m (Either String Recording)
    getRecordingById :: forall (m :: * -> *).
    MonadIO m =>
    MBID -> m (Either [Char] Recording)
    getRecordingById MBID
    mbid = do
        lbs <- Text -> Text -> [Text] -> m ByteString
    forall (m :: * -> *).
    MonadIO m =>
    Text -> Text -> [Text] -> m ByteString
    musicBrainzWSLookup Text
    "recording" (MBID -> Text
    unMBID MBID
    mbid) [Text
    "artist-credits"]
        return $ eitherDecode lbs

    getReleaseById :: MonadIO m => MBID -> m (Either String Release)
    getReleaseById :: forall (m :: * -> *).
    MonadIO m =>
    MBID -> m (Either [Char] Release)
    getReleaseById MBID
    mbid = do
        lbs <- Text -> Text -> [Text] -> m ByteString
    forall (m :: * -> *).
    MonadIO m =>
    Text -> Text -> [Text] -> m ByteString
    musicBrainzWSLookup Text
    "release" (MBID -> Text
    unMBID MBID
    mbid) [Text
    "recordings", Text
    "artist-credits"]
        return $ eitherDecode lbs

    searchReleasesByArtistAndRelease :: MonadIO m => Text -> Text -> Maybe Int -> Maybe Int -> m (Either String [(Int, Release)])
    searchReleasesByArtistAndRelease :: forall (m :: * -> *).
    MonadIO m =>
    Text
    -> Text
    -> Maybe Int
    -> Maybe Int
    -> m (Either [Char] [(Int, Release)])
    searchReleasesByArtistAndRelease Text
    artist Text
    release Maybe Int
    mlimit Maybe Int
    moffset = do
        lbs <- Text -> Text -> Maybe Int -> Maybe Int -> m ByteString
    forall (m :: * -> *).
    MonadIO m =>
    Text -> Text -> Maybe Int -> Maybe Int -> m ByteString
    musicBrainzWSSearch Text
    "release" ([Text] -> Text
    T.concat [Text
    "artist:\"", Text
    artist, Text
    "\" AND release:\"", Text
    release, Text
    "\""]) Maybe Int
    mlimit Maybe Int
    moffset
        return $ eitherDecode lbs