{-|
Module      : SimFin.Types.StockRef
Description : Type to represent a reference to a company.
Copyright   : (c) Owen Shepherd, 2022
License     : MIT
Maintainer  : owen@owen.cafe
-}

{-# LANGUAGE OverloadedStrings #-}

module SimFin.Types.StockRef
  ( StockRef(..)
  , stockRefsToQueryParams
  ) where

import Control.Arrow (first, second)
import Data.List (foldl')
import Data.List.NonEmpty (NonEmpty)
import Data.String
import Data.Text (Text)
import qualified Data.Text as T

import SimFin.Internal

-- | A stock ref is a SimSin ID or a ticker.

data StockRef = SimFinId Int | Ticker Text
  deriving Int -> StockRef -> ShowS
[StockRef] -> ShowS
StockRef -> String
(Int -> StockRef -> ShowS)
-> (StockRef -> String) -> ([StockRef] -> ShowS) -> Show StockRef
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [StockRef] -> ShowS
$cshowList :: [StockRef] -> ShowS
show :: StockRef -> String
$cshow :: StockRef -> String
showsPrec :: Int -> StockRef -> ShowS
$cshowsPrec :: Int -> StockRef -> ShowS
Show

instance IsString StockRef where
  fromString :: String -> StockRef
fromString = Text -> StockRef
Ticker (Text -> StockRef) -> (String -> Text) -> String -> StockRef
forall b c a. (b -> c) -> (a -> b) -> a -> c
. String -> Text
T.pack

-- | Collection of discriminations to discrimination of collections.

separateStockRefs :: Foldable t => t StockRef -> ([Int], [Text])
separateStockRefs :: t StockRef -> ([Int], [Text])
separateStockRefs = (([Int], [Text]) -> StockRef -> ([Int], [Text]))
-> ([Int], [Text]) -> t StockRef -> ([Int], [Text])
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' ([Int], [Text]) -> StockRef -> ([Int], [Text])
f ([], [])
  where
    f :: ([Int], [Text]) -> StockRef -> ([Int], [Text])
    f :: ([Int], [Text]) -> StockRef -> ([Int], [Text])
f ([Int], [Text])
acc (SimFinId Int
n) = ([Int] -> [Int]) -> ([Int], [Text]) -> ([Int], [Text])
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (b, d) (c, d)
first (Int
nInt -> [Int] -> [Int]
forall a. a -> [a] -> [a]
:) ([Int], [Text])
acc
    f ([Int], [Text])
acc (Ticker Text
t) = ([Text] -> [Text]) -> ([Int], [Text]) -> ([Int], [Text])
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second (Text
tText -> [Text] -> [Text]
forall a. a -> [a] -> [a]
:) ([Int], [Text])
acc

-- | Convert one or more stock references into a list of query parameters.

stockRefsToQueryParams :: NonEmpty StockRef -> [QueryParam]
stockRefsToQueryParams :: NonEmpty StockRef -> [QueryParam]
stockRefsToQueryParams NonEmpty StockRef
refs =
  let
    ([Int]
ids, [Text]
tickers) = NonEmpty StockRef -> ([Int], [Text])
forall (t :: * -> *). Foldable t => t StockRef -> ([Int], [Text])
separateStockRefs NonEmpty StockRef
refs
    tickerParam :: [QueryParam]
tickerParam = ByteString -> [Text] -> [QueryParam]
toTextCommaQueryParam ByteString
"ticker" [Text]
tickers
    idParam :: [QueryParam]
idParam = ByteString -> [Int] -> [QueryParam]
forall a. Show a => ByteString -> [a] -> [QueryParam]
toShownCommaQueryParam ByteString
"id" [Int]
ids
  in [QueryParam]
tickerParam [QueryParam] -> [QueryParam] -> [QueryParam]
forall a. Semigroup a => a -> a -> a
<> [QueryParam]
idParam