#|

src/models/ygoprodeck-classes.lisp

Yu-Gi-Oh! Pro Deck Database Interface v2

TODO Documentation; The diagram from schemacrawler would be nice.

|#

(in-package #:cl-deck-builder2.models.ygoprodeck.classes)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This is part of cardsv3 now.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defclass ygo-name-mixin ()
  ((name :accessor name-of
         :col-type :text
         :initarg :name))
  (:unique-keys name)
  (:documentation "A table for the names of all Yu-Gi-Oh! card properties.")
  (:metaclass registered-table-class))

(defclass ygo-card-name (ygo-name-mixin)
  ()
  (:documentation "A table for the names of all Yu-Gi-Oh! card names. Dark Magician, Red-Eyes Black Dragon, and so on.")
  (:metaclass registered-table-class))

(defclass ygo-card-type (ygo-name-mixin)
  ()
  (:documentation "A table for the types of Yu-Gi-Oh! cards. Spell, Flip Effect Monster, and so on.")
  (:metaclass registered-table-class))

(defclass ygo-card-frame-type (ygo-name-mixin)
  ()
  (:documentation "A table for the frame types of Yu-Gi-Oh! cards. spell, effect_pendulum, and so on.")
  (:metaclass registered-table-class))

(defclass ygo-card-race (ygo-name-mixin)
  ()
  (:documentation "A table for the races of Yu-Gi-Oh! cards. Insect, Beast, and so on.

YGOProDeck stores the kind of spell card here too, like Equip or Continuous.")
  (:metaclass registered-table-class))

(defclass ygo-card-archetype (ygo-name-mixin)
  ()
  (:documentation "A table for the archetypes of Yu-Gi-Oh! cards. Archfiend, Elemental HERO, A.I, and so on.")
  (:metaclass registered-table-class))

(defclass ygo-card-attribute (ygo-name-mixin)
  ()
  (:documentation "A table for the attributes of Yu-Gi-Oh! cards. FIRE, WIND, EARTH, DARK, and so on.")
  (:metaclass registered-table-class))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; YGO-CARD uses the PASSCODE as its UNIQUE ID, so you don't see it in
;; here, because it's added implicitly by MITO as ID slot.
(defclass ygo-card ()
  ((id :accessor ygo-passcode-of
       :col-type :integer
       :primary-key t
       :initarg :id)
   (;; Cards *always* have a UNIQUE Name, and a description. Description isn't necessarily unique.
    name :accessor name-of
         :col-type :text
         :initarg :name)
   (desc :accessor ygo-desc-of
         :col-type :text
         :initarg :desc)

   ;; Some cards pre-date Archetype (e.g. Normal Monsters)
   (archetype :accessor ygo-archetype-of
              :col-type (or ygo-card-archetype :null)
              :initarg :archetype)
   ;; Some cards don't have Attribute/ATK/DEF/Level/Scale:
   ;; - Skill
   ;; - Spell
   ;; - Trap
   (attribute :accessor ygo-attribute-of
              :col-type (or ygo-card-attribute :null)
              :initarg :attribute)
   (atk :accessor ygo-atk-of
        :col-type (or :integer :null)
        :initarg :atk)
   (def :accessor ygo-def-of
        :col-type (or :integer :null)
        :initarg :def)
   (scale :accessor ygo-scale-of
          :col-type (or :integer :null)
          :initarg :scale)
   (level :accessor ygo-level-of
          :col-type (or :integer :null)
          :initarg :level)

   ;; Every card has a Frame-Type and a Race; Even Spell and Trap cards have a Race.
   ;; YGOProDeck uses this field to keep "Continuous", or "Field" ... yuck.
   (frame-type :accessor ygo-frame-type-of
               :col-type ygo-card-frame-type
               :initarg :frame-type)
   (race :accessor ygo-race-of
         :col-type ygo-card-race
         :initarg :race)

   ;; There's a conflict with the existing lisp builtin TYPE-OF. Call
   ;; it CARD-TYPE and access with CARD-TYPE-OF.
   (card-type :accessor ygo-card-type-of
              :col-type ygo-card-type
              :initarg :type))
  (:primary-key id)
  (:auto-pk nil)
  (:documentation "A table for most info of Yu-Gi-Oh! cards.

This corresponds to the top level data for each card in the YGOProDeck API export.")
  (:metaclass registered-table-class))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; From here onward, the code depends on YGO-CARD.
(defclass ygo-card-misc-info ()
  ((passcode :accessor ygo-passcode-of
             :col-type ygo-card
             :initarg :passcode)
   (views :accessor ygo-views-of
          :col-type :integer
          :initform 0
          :initarg :views)
   (viewsweek :accessor ygo-viewsweek-of
              :col-type :integer
              :initform 0
              :initarg :viewsweek)
   (upvotes :accessor ygo-upvotes-of
            :col-type :integer
            :initform 0
            :initarg :upvotes)
   (downvotes :accessor ygo-downvotes-of
              :col-type :integer
              :initform 0
              :initarg :downvotes)
   (beta-id :accessor ygo-beta-id-of
            :col-type (or :integer :null)
            :initarg :beta--id)
   (beta-name :accessor ygo-beta-name-of
              :col-type (or ygo-name-mixin :null)
              :initarg :beta--name)
   (staple :accessor ygo-is-staple
           :col-type (or :integer :null)
           :initarg :staple)
   (konami-id :accessor ygo-konami-id-of
              :col-type :integer
              :initarg :konami--id)
   ;; This :INTEGER is just an index into this table, YGO-CARDS.
   (treated-as :accessor ygo-treated-as
               :col-type (or :null ygo-name-mixin)
               :initarg :treated--as)
   (has-effect :accessor ygo-has-effect
               :col-type (or :integer :null)
               :initarg :has--effect)
   (question-atk :accessor ygo-question-atk
                 :col-type (or :integer :null)
                 :initarg :question--atk)
   (question-def :accessor ygo-question-def
                 :col-type (or :integer :null)
                 :initarg :question--def)

   ;; When the TCG-DATE or OCG-DATE is NULL, that means it hasn't been released in TCG/OCG...
   (tcg-date :accessor ygo-tcg-date-of
             :col-type (or :timestamp :null)
             :initarg :tcg--date)
   (ocg-date :accessor ygo-ocg-date-of
             :col-type (or :timestamp :null)
             :initarg :ocg--date))
  (:metaclass registered-table-class)
  (:documentation "This corresponds to the \"misc_info\" data for each card in the YGOProDeck API export."))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Now Card Set Stuff
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defclass ygo-set-name (ygo-name-mixin)
  ()
  (:documentation "A table for the sets of Yu-Gi-Oh! cards. Lightning Overdrive, 2021 Tin of Ancient Battles, and so on.")
  (:metaclass registered-table-class))

(defclass ygo-set-code (ygo-name-mixin)
  ()
  (:documentation "A table for the set codes of Yu-Gi-Oh! cards. LOB-001, LOB-002, and so on.

SET-CODE is the full code, e.g. \"LOB-001\".

CODE is just \"001\" part, SET is just \"LOB\" part, both of which can be accessed by SPLIT-CODE.")
  (:metaclass registered-table-class))

;; Rarity => "Common", "Ghost Rare", "Ultra Rare", "Secret Rare"
(defclass ygo-set-rarity (ygo-name-mixin)
  ()
  (:documentation "A table for the rarities of Yu-Gi-Oh! cards. Common, Secret Rare, Ghost Rare, and so on.")
  (:metaclass registered-table-class))

;; jq '.[]?.card_sets[]?.set_rarity_code' < /tmp/cardinfo.json  | sort -h | uniq
(defclass ygo-set-rarity-code (ygo-name-mixin)
  ()
  (:documentation "A table for the rarity codes of Yu-Gi-Oh! cards. (C), (SR), (GUR), etc.")
  (:metaclass registered-table-class))

(defclass ygo-set-edition (ygo-name-mixin)
  ()
  (:documentation "A table for the editions of Yu-Gi-Oh! cards. 1st Edition, Unlimited, and so on.")
  (:metaclass registered-table-class))

(defclass ygo-set ()
  ((passcode :accessor ygo-passcode-of
             :col-type ygo-card
             :initarg :passcode)
   (name :accessor name-of
         :col-type ygo-set-name
         :initarg :name)
   (code :accessor ygo-code-of
         :col-type ygo-set-code
         :initarg :code)
   (rarity :accessor ygo-rarity-of
           :col-type ygo-set-rarity
           :initarg :rarity)
   (rarity-code :accessor ygo-rarity-code--of
           :col-type ygo-set-rarity-code
           :initarg :rarity-code)
   (edition :accessor ygo-edition-of
            :col-type ygo-set-edition
            :initarg :edition)

   (url :accessor ygo-url-of
        :col-type :text
        :initarg :url)

   ;; PRICE is $X,XX * 100 => XXX,00 That way we don't have to store floats at all.
   ;;
   ;; Default set price is Half a Doll Hair (0.50$) if none supplied
   (price    :accessor ygo-price-of
             :col-type :integer
             :initarg :price
             :initform 0.50
             :inflate #'currency-inflate
             :deflate #'currency-deflate))
  (:documentation "A table for the sets of Yu-Gi-Oh! cards.

This corresponds to the \"card_sets\" field in the YGOProDeck API export.")
  (:metaclass registered-table-class))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defclass ygo-linkmarker ()
  ((passcode :accessor ygo-passcode-of
             :col-type ygo-card
             :initarg :passcode)
   (bottom :accessor ygo-linkmarker-bottom
           :col-type (or :null ygo-linkmarker-name)
           :initarg :bottom)
   (bottom-left :accessor ygo-linkmarker-bottom-left
                :col-type (or :null ygo-linkmarker-name)
                :initarg :bottom-left)
   (bottom-right :accessor ygo-linkmarker-bottom-right
                 :col-type (or :null ygo-linkmarker-name)
                 :initarg :bottom-right)
   (left :accessor ygo-linkmarker-left
         :col-type (or :null ygo-linkmarker-name)
         :initarg :left)
   (right :accessor ygo-linkmarker-right
          :col-type (or :null ygo-linkmarker-name)
          :initarg :right)
   (top :accessor ygo-linkmarker-top
        :col-type (or :null ygo-linkmarker-name)
        :initarg :top)
   (top-left :accessor ygo-linkmarker-top-left
             :col-type (or :null ygo-linkmarker-name)
             :initarg :top-left)
   (top-right :accessor ygo-linkmarker-top-right
              :col-type (or :null ygo-linkmarker-name)
              :initarg :top-right))
  (:metaclass registered-table-class)
  (:documentation "A table for Yu-Gi-Oh! Link Monster Link markers.

This corresponds to the \"linkmarkers\" field in each card."))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defclass ygo-format ()
  ((passcode :accessor ygo-passcode-of
             :col-type (or :null ygo-format-name)
             :initarg :passcode)
   (common-charity :accessor ygo-common-charity-format
                   :col-type (or :null ygo-format-name)
                   :initarg :common-charity)
   (duel-links :accessor ygo-duel-links-format
               :col-type (or :null ygo-format-name)
               :initarg :duel-links)
   (edison :accessor ygo-edison-format
           :col-type (or :null ygo-format-name)
           :initarg :edison)
   (goat :accessor ygo-goat-format
         :col-type (or :null ygo-format-name)
         :initarg :goat)
   (ocg :accessor ygo-ocg-format
        :col-type (or :null ygo-format-name)
        :initarg :ocg)
   (ocg-goat :accessor ygo-ocg-goat-format
             :col-type (or :null ygo-format-name)
             :initarg :ocg-goat)
   (speed-duel :accessor ygo-speed-duel-format
               :col-type (or :null ygo-format-name)
               :initarg :speed-duel)
   (tcg :accessor ygo-tcg-format
        :col-type (or :null ygo-format-name)
        :initarg :tcg))
  (:metaclass registered-table-class)
  (:documentation "A table for Yu-Gi-Oh! rule formats.

This corresponds to the \"formats\" field in the \"misc_info\" for each card.

If the card is available in this format, e.g. listed under misc_info.formats \"TCG\", that means the card is allowed in TCG games. The YGO-TCG-FORMAT slot for this object would have a non-NIL YGO-FORMAT-NAME value."))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defclass ygo-banlist ()
  ((passcode :accessor ygo-passcode-of
             :col-type ygo-card
             :initarg :passcode)
   (ban-goat :accessor ygo-ban-goat
             :col-type (or :null ygo-banlist-name)
             :initarg :ban--goat)
   (ban-ocg  :accessor ygo-ban-ocg
             :col-type (or :null ygo-banlist-name)
             :initarg :ban--ocg)
   (ban-tcg  :accessor ygo-ban-tcg
             :col-type (or :null ygo-banlist-name)
             :initarg :ban--tcg))
  (:unique-keys passcode)
  (:metaclass registered-table-class)
  (:documentation "A table for Yu-Gi-Oh! rule banlist.

This corresponds to the \"banlist_info\" field  for each card."))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defclass ygo-alternative-artwork ()
  ((passcode :accessor ygo-passcode-of
             :col-type ygo-card
             :initarg :passcode)
   (alternate :accessor ygo-alternate-id-of
              :col-type ygo-card
              :initarg :alternate))
  (:metaclass registered-table-class)
  (:documentation "A table for Yu-Gi-Oh! alternative artwork.

This corresponds to the \"card_images\" array for each card."))

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defclass ygo-price ()
  ((passcode :accessor ygo-passcode-of
             :col-type ygo-card
             :initarg :passcode
             :deflate #'currency-deflate
             :inflate #'currency-inflate)
   (cardmarket-price :accessor ygo-cardmarket-price-of
                     :col-type :integer
                     :initarg :cardmarket--price
                     :deflate #'currency-deflate
                     :inflate #'currency-inflate)
   (tcgplayer-price :accessor ygo-tcgplayer-price-of
                    :col-type :integer
                    :initarg :tcgplayer--price
                    :deflate #'currency-deflate
                    :inflate #'currency-inflate)
   (ebay-price :accessor ygo-ebay-price-of
               :col-type :integer
               :initarg :ebay--price
               :deflate #'currency-deflate
               :inflate #'currency-inflate)
   (amazon-price :accessor ygo-amazon-price-of
                 :col-type :integer
                 :initarg :amazon--price
                 :deflate #'currency-deflate
                 :inflate #'currency-inflate)
   (coolstuffinc-price :accessor ygo-coolstuffinc-price-of
                       :col-type :integer
                       :initarg :coolstuffinc--price
                       :deflate #'currency-deflate
                       :inflate #'currency-inflate))
  (:metaclass registered-table-class)
  (:documentation "A table for Yu-Gi-Oh! pricing information. Represents the API information about Card Pricing. Encapsulates the following fields:
- Passcode
- CardMarket
- TCGPlayer
- eBay
- Amazon
- CoolStuffInc

This corresponds to the \"card_prices\" array for each card."))

;; YGO-FORMAT-NAME, YGO-LINKMARKER-NAME, YGO-BANLIST-NAME,
;; YGO-SET-RARITY-CODE, and the like have moved to YGOPRODECK.FIELDS.

(defclass ygo-set-item ()
  ((item :accessor item-of
         :initarg :item
         :col-type ygo-set)
   (variant :accessor variant-of
            :initarg :variant
            :col-type variant-condition)
   (qty :accessor qty-of
        :col-type :integer
        :initform 0
        :initarg :qty)
   (opt-qty :accessor opt-qty-of
            :col-type :integer
            :initform 0
            :initarg :opt-qty)
   (;; 10 cent buy price
    buy-price :accessor buy-price-of
              :col-type :integer
              :initform 0.10
              :initarg :buy-price
              :inflate #'currency-inflate
              :deflate #'currency-deflate)
   (;; 50 cent sell price
    sell-price :accessor sell-price-of
               :col-type :integer
               :initform 0.50
               :initarg :sell-price
               :inflate #'currency-inflate
               :deflate #'currency-deflate))
  (:metaclass registered-table-class)
  (:documentation "YGO-SET + VARIANT-CONDITION relationship table."))


#|
;;;; models/ygoprodeck.lisp
  (defstruct ygoprodeck-item
    (:documentation "Represents the top level API information queried from YGOProDeck. Encapsulates the following fields: ~Passcode~,~Name~,~Type~, ~Frame Type~, ~Documentation~,~Race~,~ATK~, ~DEF~,~Level~,~Attribute~, and ~Archetype~."))
  (defstruct ygoprodeck-card-set
    (:documentation "Represents the API information about Card Sets. Encapsulates the following fields: ~Passcode~,~Name~,~Code~, ~Rarity~, ~Rarity-code~, and ~Price~."))
  (defstruct ygoprodeck-card-image
    (:documentation "Card images. We don't use this much."))
  (defstruct ygoprodeck-card-price
  (defun drop-table-ygoprodeck-data
      (:documentation "Destroy the table for this data."))
  (defun create-table-ygoprodeck-data
      (:documentation "Create the corresponding database structure for the YGOProDeck API data import."))
  (defun json-import-ygoprodeck-data
      (:arguments
       ((data "The data to be imported."))
       :documentation "Import the base API data (ATK, DEF,Level, ...) information from the Card Info API data."))
  (defun json-import-ygoprodeck-card-images
      (:arguments
       ((data "The data to be imported."))
       :documentation "Import the images information from the Card Info API data."))
  (defun json-import-ygoprodeck-card-prices
      (:arguments
       ((data "The data to be imported."))
       :documentation "Import the pricing information from the Card Info API data."))
  (defun json-import-ygoprodeck-card-sets
      (:arguments
       ((data "The data to be imported."))
       :documentation "Import the card set information from the Card Info API data."))
  (defun json-import-ygoprodeck-banlist-info
      (:arguments
       ((data "The data to be imported."))
       :documentation "Import the banlist information from the Card Info API data."))
  (defun json-import-ygoprodeck
      (:arguments
       ((json "The JSON query to iterate over. Response from YGOProDeck API."))
       :documentation "Import YGOProDeck data. Wraps the ~JSON-IMPORT-*~ functions."))
  (defun card-rarity-list
      (:documentation "List all card rarities."))
  (defun card-code-list
      (:documentation "List all card set codes."))

|#
