content: module Data.Schematic.Generator where
  
  import           Data.Maybe
  import           Data.Schematic.Generator.Regex
  import {-# SOURCE #-} Data.Schematic.Schema
  import           Data.Schematic.Verifier
  import           Data.Scientific
  import           Data.Text (Text, pack)
  import qualified Data.Vector as V
  import           Test.SmallCheck.Series
  
  maxHigh :: Int
  maxHigh = 30
  
  minLow :: Int
  minLow = 2
  
  textLengthSeries :: Monad m => [VerifiedTextConstraint] -> Series m Text
  textLengthSeries =
    \case
      [VTEq eq]        -> pure $ pack $ take (fromIntegral eq) $ cycle "sample"
      [VTBounds ml mh] -> do
        let
          l = fromMaybe minLow (fromIntegral <$> ml) + 1
          h = fromMaybe maxHigh (fromIntegral <$> mh) - 1
        n <- generate $ \depth -> take depth [l .. h]
        pure $ pack $ take (fromIntegral n) $ cycle "sample"
      _                -> pure "error"
  
  textEnumSeries :: Monad m => [Text] -> Series m Text
  textEnumSeries enum = generate $ \depth -> take depth enum
  
  textSeries :: Monad m => [DemotedTextConstraint] -> Series m Text
  textSeries cs = do
    let mvcs = verifyTextConstraints cs
    case mvcs of
      Just vcs -> do
        n <- textSeries' vcs
        pure n
      Nothing  -> pure "error"
  
  textSeries' :: Monad m => [VerifiedTextConstraint] -> Series m Text
  textSeries' [] = pure "sample"
  textSeries' vcs = do
    let enums = listToMaybe [x | VTEnum x <- vcs]
    case enums of
      Just e -> textEnumSeries e
      Nothing -> do
        let regexps = listToMaybe [x | VTRegex x _ _ <- vcs]
        case regexps of
          Just e  -> regexSeries e
          Nothing -> textLengthSeries vcs
  
  numberSeries :: Monad m => [DemotedNumberConstraint] -> Series m Scientific
  numberSeries cs = do
    let mvcs = verifyNumberConstraints cs
    case mvcs of
      Just vcs -> do
        n <- numberSeries' vcs
        pure $ n
      Nothing -> pure 0
  
  numberSeries' :: Monad m => VerifiedNumberConstraint -> Series m Scientific
  numberSeries' =
    \case
      VNEq eq -> pure $ fromIntegral eq
      VNBounds ml mh -> do
        let l = fromMaybe minLow (fromIntegral <$> ml) + 1
            h = fromMaybe maxHigh (fromIntegral <$> mh) - 1
        n <- generate $ \depth -> take depth [l .. h]
        pure $ fromIntegral n
  
  arraySeries
    :: (Monad m, Serial m (JsonRepr s))
    => [DemotedArrayConstraint]
    -> Series m (V.Vector (JsonRepr s))
  arraySeries cs = do
    let mvcs = verifyArrayConstraint cs
    case mvcs of
      Just vcs -> arraySeries' vcs
      Nothing  -> pure V.empty
  
  arraySeries'
    :: forall m s. (Monad m, Serial m (JsonRepr s))
    => Maybe VerifiedArrayConstraint
    -> Series m (V.Vector (JsonRepr s))
  arraySeries' ml = do
    objs <- V.replicateM (maybe minRepeat f ml) (series :: Series m (JsonRepr s))
    pure $ objs
    where
      f (VAEq l) = fromIntegral l
  