-- |
-- Module: Symtegration.Integration.Term
-- Description: Integrates a single term.
-- Copyright: Copyright 2025 Yoo Chung
-- License: Apache-2.0
-- Maintainer: dev@chungyc.org
module Symtegration.Integration.Term (integrate) where

import Data.Foldable (asum)
import Data.Text (Text)
import Symtegration.Integration.Factor
import Symtegration.Symbolic
import Symtegration.Symbolic.Simplify

-- $setup
-- >>> import Symtegration.Symbolic.Haskell
-- >>> import Symtegration.Symbolic.Simplify

-- | Integrate a single term, separating out the constant factor and
-- applying direct integration methods to the non-constant factor.
--
-- >>> import Symtegration.Integration.Trigonometric qualified as T
-- >>> let f = "a" * sin "x"
-- >>> T.integrate "x" f
-- Nothing
-- >>> let g = integrate [T.integrate] "x" f
-- >>> toHaskell . simplify <$> g
-- Just "(-1) * a * cos x"
--
-- Assumes the expression has had algebraic ring ordering applied.
integrate ::
  -- | Functions for directly integrating the non-constant factor.
  [Text -> Expression -> Maybe Expression] ->
  -- | The variable being integrated over.
  Text ->
  -- | The expression being integrated.
  Expression ->
  -- | The integral, if successful.
  Maybe Expression
integrate :: [Text -> Expression -> Maybe Expression]
-> Text -> Expression -> Maybe Expression
integrate [Text -> Expression -> Maybe Expression]
fs Text
v Expression
e = [Maybe Expression] -> Maybe Expression
forall (t :: * -> *) (f :: * -> *) a.
(Foldable t, Alternative f) =>
t (f a) -> f a
asum ([Maybe Expression] -> Maybe Expression)
-> [Maybe Expression] -> Maybe Expression
forall a b. (a -> b) -> a -> b
$ ((Text -> Expression -> Maybe Expression) -> Maybe Expression)
-> [Text -> Expression -> Maybe Expression] -> [Maybe Expression]
forall a b. (a -> b) -> [a] -> [b]
map (\Text -> Expression -> Maybe Expression
f -> Expression -> Expression -> Expression
(:*:) Expression
c (Expression -> Expression) -> Maybe Expression -> Maybe Expression
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Text -> Expression -> Maybe Expression
f Text
v Expression
u) [Text -> Expression -> Maybe Expression]
fs
  where
    e' :: Expression
e' = Text -> Expression -> Expression
simplifyForVariable Text
v Expression
e
    (Expression
c, Expression
u) = Text -> Expression -> (Expression, Expression)
factor Text
v Expression
e'