{-# 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 :: Text -> Text -> [Text] -> m ByteString
musicBrainzWSLookup reqtype :: Text
reqtype param :: Text
param incparams :: [Text]
incparams = do
    let url :: [Char]
url = "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]
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 [] = ""
        incs xs :: [Text]
xs = ("?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]) -> ([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 = "&fmt=json"

musicBrainzWSSearch :: MonadIO m => Text -> Text -> Maybe Int -> Maybe Int -> m BL.ByteString
musicBrainzWSSearch :: Text -> Text -> Maybe Int -> Maybe Int -> m ByteString
musicBrainzWSSearch reqtype :: Text
reqtype query :: Text
query mlimit :: Maybe Int
mlimit moffset :: Maybe Int
moffset = do
    let url :: [Char]
url = "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]
++ "/?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 Nothing = ""
        limit (Just l :: a
l) = "&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 Nothing = ""
        offset (Just o :: a
o) = "&offset=" [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ a -> [Char]
forall a. Show a => a -> [Char]
show a
o
        fj :: [Char]
fj = "&fmt=json"

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

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

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