module Product where

import Control.Monad.Reader
import Test.HUnit
import Data.List (intercalate)

-- Beispielwerte
-- 1 Euro kostet 1,14 Dollar
-- 1 Euro kostet 1,05 CHF

data Config = Config { dollarRate :: Double, chfRate :: Double }

data Price
  = PriceEuro Double
  | PriceDollar Double
  | PriceCHF Double

data Product
  = Product
  { productName :: String
  , productQuantity :: Int
  , productSinglePrice :: Price
  }

data Invoice
  = Invoice
  { invoiceCustomer :: String
  , invoiceProducts :: [Product]
  }

sampleInvoice :: Invoice
sampleInvoice =
  Invoice
  { invoiceCustomer = "Stefan Wehr"
  , invoiceProducts = [p1, p2]
  }
  where
    p1 = Product "Feinstimmer Geige" 2 (PriceDollar 9.1086)
    p2 = Product "HX Effects" 1 (PriceCHF 523.95)

formatInvoice :: Invoice -> Reader Config String
formatInvoice invoice = do
    productStrings <- traverse formatProduct (invoiceProducts invoice)
    let customer = invoiceCustomer invoice ++ "\n\n"
    let products = intercalate "\n" productStrings
    return $ customer ++ products

formatProduct :: Product -> Reader Config String
formatProduct product = do
  price <- convertPrice $ productSinglePrice product
  return $ productName product ++ " (" ++ show (productQuantity product) ++ "x) " ++ show price ++ " EUR"

convertPrice :: Price -> Reader Config Double
convertPrice price = do
  priceRates <- ask
  case price of
    PriceEuro euro -> return euro
    PriceDollar dollar -> return $ if dollarRate priceRates <= 0 then error "Dollar rate is 0 or negative" else dollar / dollarRate priceRates
    PriceCHF chf -> return $ if chfRate priceRates <= 0 then error "CHF rate is 0 or negative." else chf / chfRate priceRates

-- Tests
allTests :: Test
allTests = TestList [
  TestLabel "testFormatInvoice" testFormatInvoice
  ]

testFormatInvoice :: Test
testFormatInvoice = TestCase $ do
  let config = Config 1.14 1.05
  let formattedInvoice = runReader (formatInvoice sampleInvoice) config
  assertEqual "test1" "Stefan Wehr\n\nFeinstimmer Geige (2x) 7.99 EUR\nHX Effects (1x) 499.0 EUR" formattedInvoice