content: module Note where
  
  import Data.Aeson (
    FromJSON (parseJSON),
    ToJSON,
    withObject,
    (.:),
    (.:?),
   )
  import Data.Csv qualified as Csv
  import Data.Text as T (Text, intercalate, toLower)
  import Data.ULID (ulidFromInteger)
  import Database.SQLite.Simple (FromRow, ToRow, field, fromRow, toRow)
  import Database.SQLite.Simple.ToField (toField)
  import Protolude (
    Alternative ((<|>)),
    Applicative (pure),
    Eq,
    Functor (fmap),
    Generic,
    Hashable (hash),
    Integral (toInteger),
    Num (abs),
    Semigroup ((<>)),
    Show,
    encodeUtf8,
    fromMaybe,
    hush,
    show,
    ($),
    (.),
    (<$>),
    (<&>),
    (<*>),
   )
  
  
  data Note = Note
    { ulid :: Text
    , body :: Text
    }
    deriving (Generic, Show, Eq)
  
  
  instance ToRow Note where
    toRow Note{ulid = ulid, body = body} =
      [ toField ulid
      , toField body
      ]
  
  
  instance FromRow Note where
    fromRow = Note <$> field <*> field
  
  
  instance ToJSON Note
  
  
  instance FromJSON Note where
    parseJSON = withObject "note" $ \o -> do
      o_ulid <- o .:? "ulid"
  
      let
        ulidGenerated = (ulidFromInteger . abs . toInteger . hash) o
        ulid =
          T.toLower $
            fromMaybe "" $
              o_ulid <|> hush (ulidGenerated <&> show)
  
      body <- o .: "body"
  
      pure Note{..}
  
  
  instance Hashable Note
  
  
  instance Csv.ToField [Note] where
    toField =
      encodeUtf8
        . T.intercalate ","
        . fmap (\Note{ulid = ulid, body = body} -> ulid <> ": " <> body)
  