-- Exercise 7 -----------------------------------------

undoTs :: Map String Integer -> [TId] -> [Transaction]
undoTs flow_map tid = zipWith (\id (from, to, amount) -> Transaction from to amount id) tid $ repay (getPayers flow_map) (getPayees flow_map)
  where repay :: [(String, Integer)] -> [(String, Integer)] -> [(String, String, Integer)]
        repay [] _ = []
        repay _ [] = []
        repay (payer:payers) (payee:payees)
          | minimum_amount == (snd payer) = (from_name, to_name, minimum_amount) : repay payers ((to_name, to_amount):payees)
          | minimum_amount == ((negate . snd) payee) = (from_name, to_name, minimum_amount) : repay ((from_name, from_amount):payers) payees
          | otherwise = repay payers payees
          where minimum_amount = min (snd payer) ((negate . snd) payee)
                from_name = fst payer
                from_amount = (snd payer) - minimum_amount
                to_name = fst payee
                to_amount = (snd payee) + minimum_amount
        getPayers = List.sortBy descendingOrder . Map.toList . Map.filter (>0)
        getPayees = reverse . List.sortBy descendingOrder . Map.toList . Map.filter (<0)
        descendingOrder (_, x) (_, y) = compare y x

-- Exercise 8 -----------------------------------------
undoTs :: Map String Integer -> [TId] -> [Transaction]
undoTs flow_map tid = zipWith (\id (from, to, amount) -> Transaction from to amount id) tid $ repay (getPayers flow_map) (getPayees flow_map)
  where repay :: [(String, Integer)] -> [(String, Integer)] -> [(String, String, Integer)]
        repay [] _ = []
        repay _ [] = []
        repay (payer:payers) (payee:payees)
          | minimum_amount == (snd payer) = (from_name, to_name, minimum_amount) : repay payers ((to_name, to_amount):payees)
          | minimum_amount == ((negate . snd) payee) = (from_name, to_name, minimum_amount) : repay ((from_name, from_amount):payers) payees
          | otherwise = repay payers payees
          where minimum_amount = min (snd payer) ((negate . snd) payee)
                from_name = fst payer
                from_amount = (snd payer) - minimum_amount
                to_name = fst payee
                to_amount = (snd payee) + minimum_amount
        getPayers = List.sortBy descendingOrder . Map.toList . Map.filter (>0)
        getPayees = reverse . List.sortBy descendingOrder . Map.toList . Map.filter (<0)
        descendingOrder (_, x) (_, y) = compare y x

-- Exercise 8 -----------------------------------------
undoTs flow_map tid = zipWith (\id (from, to, amount) -> Transaction from to amount id) tid $ repay (getPayers flow_map) (getPayees flow_map)
  where repay :: [(String, Integer)] -> [(String, Integer)] -> [(String, String, Integer)]
        repay [] _ = []
        repay _ [] = []
        repay (payer:payers) (payee:payees)
          | minimum_amount == (snd payer) = (from_name, to_name, minimum_amount) : repay payers ((to_name, to_amount):payees)
          | minimum_amount == ((negate . snd) payee) = (from_name, to_name, minimum_amount) : repay ((from_name, from_amount):payers) payees
          | otherwise = repay payers payees
          where minimum_amount = min (snd payer) ((negate . snd) payee)
                from_name = fst payer
                from_amount = (snd payer) - minimum_amount
                to_name = fst payee
                to_amount = (snd payee) + minimum_amount
        getPayers = List.sortBy descendingOrder . Map.toList . Map.filter (>0)
        getPayees = reverse . List.sortBy descendingOrder . Map.toList . Map.filter (<0)
        descendingOrder (_, x) (_, y) = compare y x

-- Exercise 8 -----------------------------------------