+{-# LANGUAGE StrictData #-}
+
+module Wiktionary where
+
+-- import Data.List qualified as List
+import Utils.Generics qualified as Gen
+import Utils.JSON qualified as JSON
+import Utils.Prelude
+import Utils.SQL qualified as SQL
+
+import Control.Monad.Trans.Reader (ReaderT (..))
+import Control.Monad.Trans.State.Strict (StateT (..))
+import Database.SQLite.Simple.Internal (RowParser (..))
+
+-- import Data.ByteString (ByteString)
+-- import Database.SQLite3 qualified as SQL.Base
+-- import Database.SQLite3.Direct qualified as SQL.Direct
+-- import Database.SQLite3.Bindings qualified as SQL.Direct.Bindings
+-- import Control.Exception (bracket)
+-- import Data.Text.Encoding qualified as Text
+
+-- | Tries to follow the schema at:
+-- https://kaikki.org/dictionary/errors/mapping/index.html
+data Wiktionary = Wiktionary
+ { wiktionary_abbreviation :: Maybe [Abbreviation]
+ , wiktionary_anagrams :: Maybe [Anagram]
+ , wiktionary_antonyms :: Maybe JSON.Value
+ , wiktionary_categories :: Maybe [ShortText]
+ , wiktionary_derived :: Maybe JSON.Value
+ , wiktionary_etymology_examples :: Maybe JSON.Value
+ , wiktionary_etymology_texts :: [ShortText]
+ , wiktionary_forms :: Maybe [Form]
+ , wiktionary_holonyms :: Maybe JSON.Value
+ , wiktionary_hypernyms :: Maybe JSON.Value
+ , wiktionary_hyponyms :: Maybe JSON.Value
+ , wiktionary_lang :: Maybe ShortText
+ , wiktionary_lang_code :: Maybe ShortText
+ , wiktionary_meronyms :: Maybe JSON.Value
+ , wiktionary_notes :: Maybe JSON.Value
+ , wiktionary_paronyms :: Maybe JSON.Value
+ , wiktionary_pos :: Maybe ShortText
+ , wiktionary_pos_title :: Maybe ShortText
+ , wiktionary_proverbs :: Maybe JSON.Value
+ , wiktionary_raw_tags :: Maybe [ShortText]
+ , wiktionary_redirect :: Maybe ShortText
+ , wiktionary_related :: Maybe JSON.Value
+ , wiktionary_senses :: Maybe [Sense]
+ , wiktionary_sounds :: [Sound]
+ , wiktionary_synonyms :: Maybe [Synonym]
+ , wiktionary_tags :: Maybe [ShortText]
+ , wiktionary_title :: Maybe JSON.Value
+ , wiktionary_translations :: Maybe JSON.Value
+ , wiktionary_troponyms :: Maybe JSON.Value
+ , wiktionary_word :: Maybe ShortText
+ -- ^ Yes, the word can be missing,
+ -- eg. when `wiktionary_pos` is `"hard-redirect"`.
+ }
+ deriving (Eq, Show, Generic)
+ deriving
+ (JSON.ToJSON, JSON.FromJSON)
+ via (JSON.GenericallyWithOptions Wiktionary)
+ deriving
+ (SQL.ToRow {-, SQL.FromRow-})
+ via (SQL.GenericallyWithOptions Wiktionary)
+
+instance SQL.FromRow Wiktionary where
+ fromRow = SQL.gfromRowWithErrorContext <&> Gen.to
+
+data Anagram = Anagram
+ { anagram_word :: ShortText
+ }
+ deriving (Eq, Show, Generic)
+ deriving
+ (JSON.ToJSON, JSON.FromJSON)
+ via (JSON.GenericallyWithOptions Anagram)
+
+data Sense = Sense
+ { sense_alt_of :: Maybe JSON.Value
+ , sense_categories :: Maybe [ShortText]
+ , sense_examples :: Maybe JSON.Value
+ , sense_form_of :: Maybe JSON.Value
+ , sense_glosses :: Maybe [ShortText]
+ , sense_note :: Maybe JSON.Value
+ , sense_raw_tags :: Maybe JSON.Value
+ , sense_tags :: Maybe JSON.Value
+ , sense_topics :: Maybe JSON.Value
+ }
+ deriving (Eq, Show, Generic)
+ deriving
+ (JSON.ToJSON, JSON.FromJSON)
+ via (JSON.GenericallyWithOptions Sense)
+
+data Synonym = Synonym
+ { synonym_alt :: Maybe JSON.Value
+ , synonym_raw_tags :: Maybe JSON.Value
+ , synonym_roman :: Maybe JSON.Value
+ , synonym_sense :: Maybe JSON.Value
+ , synonym_sense_index :: Maybe JSON.Value
+ , synonym_tags :: Maybe JSON.Value
+ , synonym_topics :: Maybe JSON.Value
+ , synonym_translation :: Maybe JSON.Value
+ , synonym_word :: ShortText
+ }
+ deriving (Eq, Show, Generic)
+ deriving
+ (JSON.ToJSON, JSON.FromJSON)
+ via (JSON.GenericallyWithOptions Synonym)
+
+data Abbreviation = Abbreviation
+ { abbreviation_raw_tags :: Maybe JSON.Value
+ , abbreviation_roman :: Maybe ShortText
+ , abbreviation_sense :: Maybe JSON.Value
+ , abbreviation_sense_index :: Maybe JSON.Value
+ , abbreviation_tags :: Maybe JSON.Value
+ , abbreviation_topics :: Maybe JSON.Value
+ , abbreviation_translation :: Maybe JSON.Value
+ , abbreviation_word :: Maybe ShortText
+ }
+ deriving (Eq, Show, Generic)
+ deriving
+ (JSON.ToJSON, JSON.FromJSON)
+ via (JSON.GenericallyWithOptions Abbreviation)
+
+data Form = Form
+ { form_form :: ShortText
+ , form_ipas :: Maybe [ShortText]
+ , form_raw_tags :: Maybe JSON.Value
+ , form_sense :: Maybe JSON.Value
+ , form_sense_index :: Maybe JSON.Value
+ , form_source :: Maybe ShortText
+ , form_tags :: Maybe [ShortText]
+ , form_hiragana :: Maybe ShortText
+ , form_roman :: Maybe ShortText
+ }
+ deriving (Eq, Show, Generic)
+ deriving
+ (JSON.ToJSON, JSON.FromJSON)
+ via (JSON.GenericallyWithOptions Form)
+
+data Sound = Sound
+ { sound_audio :: Maybe ShortText
+ , sound_homophone :: Maybe JSON.Value
+ , sound_ipa :: Maybe ShortText
+ , sound_mp3_url :: Maybe ShortText
+ , sound_oga_url :: Maybe ShortText
+ , sound_opus_url :: Maybe ShortText
+ , sound_ogg_url :: Maybe ShortText
+ , sound_flac_url :: Maybe ShortText
+ , sound_raw_tags :: Maybe [ShortText]
+ , sound_rhymes :: Maybe JSON.Value
+ , sound_roman :: Maybe JSON.Value
+ , sound_tags :: Maybe JSON.Value
+ , sound_wav_url :: Maybe ShortText
+ , sound_zh_pron :: Maybe JSON.Value
+ }
+ deriving (Eq, Show, Generic)
+ deriving
+ (JSON.ToJSON, JSON.FromJSON)
+ via (JSON.GenericallyWithOptions Sound)
+
+type LangCode = ShortText