module Data.Owoify.Owoify
  ( owoify
  , uwuify
  , uvuify
  , OwoifyLevel(..)
  )
  where

import Prelude hiding (words)

import Data.Functor ((<&>))
import Data.Text.Lazy (Text, intercalate, pack)
import Text.RE.PCRE.Text.Lazy ((*=~), compileRegex, Matches, matches, RE)
import Data.Owoify.Internal.Parser.OwoifyParser (count, OError, OwoifyParser, runParser)
import Data.Owoify.Internal.Data.Presets (owoMappingList, specificWordMappingList, uvuMappingList, uwuMappingList)
import Data.Owoify.Internal.Entity.Word (InnerWord(InnerWord), toText)
import Data.Owoify.Internal.Util.Interleave (interleave)

-- | Levels to denote owoness.
data OwoifyLevel = Owo | Uwu | Uvu

extractWords :: MonadFail f => String -> Text -> f [Text]
extractWords :: forall (f :: * -> *). MonadFail f => String -> Text -> f [Text]
extractWords String
pattern Text
s =
  forall (m :: * -> *).
(Functor m, Monad m, MonadFail m) =>
String -> m RE
compileRegex String
pattern forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> (Text
s Text -> RE -> Matches Text
*=~) forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> forall a. Matches a -> [a]
matches

words :: Text -> IO [Text]
words :: Text -> IO [Text]
words = forall (f :: * -> *). MonadFail f => String -> Text -> f [Text]
extractWords String
"[^\\s]+"

spaces :: Text -> IO [Text]
spaces :: Text -> IO [Text]
spaces = forall (f :: * -> *). MonadFail f => String -> Text -> f [Text]
extractWords String
"\\s+"

-- | Owoify source text using the specified level and turn text into nonsensical babyspeaks.
--
-- Examples:
--
-- >>> owoify (Data.Text.Lazy.pack "Hello World!") Owo
-- Hewwo World
owoify :: Text -> OwoifyLevel -> IO Text
owoify :: Text -> OwoifyLevel -> IO Text
owoify Text
source OwoifyLevel
level = do
  [Text]
w <- Text -> IO [Text]
words Text
source
  [Text]
s <- Text -> IO [Text]
spaces Text
source
  let n :: Int
n = forall (t :: * -> *) a. Foldable t => t a -> Int
length [Text]
w
  let parsers :: OwoifyParser OError [IO InnerWord]
parsers = forall (t :: * -> *) (m :: * -> *) e.
(Foldable t, Monad m, OwoifyError e) =>
Int -> t (InnerWord -> m InnerWord) -> OwoifyParser e [m InnerWord]
count Int
n forall a b. (a -> b) -> a -> b
$ [InnerWord -> IO InnerWord]
specificWordMappingList forall a. Semigroup a => a -> a -> a
<> (case OwoifyLevel
level of
        OwoifyLevel
Owo -> [InnerWord -> IO InnerWord]
owoMappingList
        OwoifyLevel
Uwu -> [InnerWord -> IO InnerWord]
uwuMappingList forall a. Semigroup a => a -> a -> a
<> [InnerWord -> IO InnerWord]
owoMappingList
        OwoifyLevel
Uvu -> [InnerWord -> IO InnerWord]
uvuMappingList forall a. Semigroup a => a -> a -> a
<> [InnerWord -> IO InnerWord]
uwuMappingList forall a. Semigroup a => a -> a -> a
<> [InnerWord -> IO InnerWord]
owoMappingList) :: OwoifyParser OError [IO InnerWord]
  let result :: Either OError (OwoifyResult [IO InnerWord])
result = forall e a.
OwoifyError e =>
OwoifyParser e a -> [Text] -> Either e (OwoifyResult a)
runParser OwoifyParser OError [IO InnerWord]
parsers [Text]
w
  case Either OError (OwoifyResult [IO InnerWord])
result of
    Left OError
e -> do
      forall a. HasCallStack => String -> a
error forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> String
show OError
e
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ String -> Text
pack String
""
    Right ([Text]
_, [IO InnerWord]
transformedWords) -> do
      [Text]
wordsList <- forall (t :: * -> *) (m :: * -> *) a.
(Traversable t, Monad m) =>
t (m a) -> m (t a)
sequence [IO InnerWord]
transformedWords forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap InnerWord -> Text
toText
      let interleaved :: [Text]
interleaved = forall a. [a] -> [a]
reverse forall a b. (a -> b) -> a -> b
$ forall a. [a] -> [a] -> [a]
interleave [Text]
wordsList [Text]
s
      forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ Text -> [Text] -> Text
intercalate (String -> Text
pack String
"") [Text]
interleaved

-- | Owoify source text using Uwu owoness level and turn text into nonsensical babyspeaks.
--
-- Examples:
--
-- >>> uwuify (Data.Text.Lazy.pack "Hello World!")
-- NOW "Hewwo WowwdUvU"
uwuify :: Text -> IO Text
uwuify :: Text -> IO Text
uwuify Text
source = Text -> OwoifyLevel -> IO Text
owoify Text
source OwoifyLevel
Uwu

-- | Owoify source text using Uwu owoness level and turn text into nonsensical babyspeaks.
--
-- Examples:
--
-- >>> uvuify (Data.Text.Lazy.pack "Hello World!")
-- "Hewwowo Wowwd>w<"
uvuify :: Text -> IO Text
uvuify :: Text -> IO Text
uvuify Text
source = Text -> OwoifyLevel -> IO Text
owoify Text
source OwoifyLevel
Uvu