import 'dotenv/config'
import 'https'
import fs from 'fs'
import { Readable } from 'stream'
import { finished } from 'stream/promises'
import pg from 'pg'
const { Client } = pg

console.log("Fetching latest Scryfall Bulk Data URL...")
const bulkDataApi = await fetch('https://api.scryfall.com/bulk-data')
const bulkDataApiJson = await bulkDataApi.json()
const bulkDataDownloadUrl = bulkDataApiJson.data.filter((obj) => obj.type == "default_cards")[0].download_uri

console.log("Downloading latest Scryfall Bulk Data...")
const stream = fs.createWriteStream(import.meta.dirname + '/data/scryfall_data.json');
const { body } = await fetch(bulkDataDownloadUrl);
await finished(Readable.fromWeb(body).pipe(stream));

console.log("Fetching latest sets list from Scryfall...")
const scryfallSets = await fetch('https://api.scryfall.com/sets');
console.log('Status Code:', scryfallSets.status);
const sets = await scryfallSets.json();

// Read the data from the exported fr_cards.json extracted from Scryfall Bulk Data
console.log("Reading Bulk Data...")
const fileBytes = fs.readFileSync(import.meta.dirname + '/data/scryfall_data.json')
let scryfallData = JSON.parse(fileBytes)

// Connect to postgres database
const client = new Client({
  user: process.env.DATABASE_USER,
  password: process.env.DATABASE_PASSWORD,
  host: process.env.DATABASE_HOST,
  port: process.env.DATABASE_PORT,
  database: process.env.DATABASE_DB
})
await client.connect()

const two_faced_layouts = ["transform","modal_dfc","double_faced_token","reversible_card"]

console.log("Starting updating database...")
try {
  const setRes = await client.query('SELECT id FROM set')
  const preUpdateSetRows = setRes.rows
  let preUpdateSetIds = []
  preUpdateSetRows.forEach(element => {
    preUpdateSetIds.push(element.id)
  });

  for (const set of sets.data) {
    if(!preUpdateSetIds.includes(set.id)){
      await client.query('INSERT INTO set(id, name_en, sanitized_name, code, set_type, released_at, icon_svg_uri) VALUES($1, $2, $3, $4, $5, $6, $7)', [set.id, set.name, set.name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase(), set.code, set.set_type, set.released_at, set.icon_svg_uri])
    }
  }


  // Select already imported cards in database
  const cardsRes = await client.query('SELECT id FROM carte')
  const preUpdateCardsRows = cardsRes.rows
  let preUpdateCardsIds = []
  preUpdateCardsRows.forEach(element => {
    preUpdateCardsIds.push(element.id)
  });

  // Define counter for logging
  let total_inserted = 0 
  let total_skipped = 0
  let total_updated = 0

  const total_cards = scryfallData.length

  // For each card check if we need to upload it to the database
  for (const carte of scryfallData) {
    const total_processed = total_skipped + total_updated + total_inserted
    if ((total_processed) % 1000 == 0) {
      console.log(total_processed + "/" + total_cards) 
    }

    if(carte.legalities.commander != "not_legal" && carte.border_color != "borderless" && !carte.full_art && !carte.textless && carte.cardmarket_id && (carte.frame_effects == undefined || ["extendedart", "showcase"].every((frame_effect) => !carte.frame_effects.includes(frame_effect)))) {

      if(!preUpdateCardsIds.includes(carte.id)){
        let type = ""
        const layout = carte.layout
        const card_type = (carte.type_line == undefined) ? carte.card_faces[0].type_line.toLowerCase() : carte.type_line.toLowerCase()
        
        let promo = (carte.promo_types == undefined) ? false : true
        let can_be_commander = (card_type.includes("legendary") && (card_type.includes("creature") || card_type.includes("planeswalker"))) ? true : false
         


        if(card_type.includes("creature")){
          type = "creature"
        } else if (card_type.includes("planeswalker")) {
          type = "planeswalker"
        } else if (card_type.includes("artifact")) {
          type = "artifact"
        } else if (card_type.includes("instant")) {
          type = "instant"
        } else if (card_type.includes("enchantment")) {
          type = "enchantment"
        } else if (card_type.includes("sorcery")) {
          type = "sorcery"
        } else if (card_type.includes("land")) {
          type = "land"
        }

        try {
          if(two_faced_layouts.includes(layout)) {
            const addingCardsQuery = await client.query('INSERT INTO carte(id, name, released_at, small_image, small_image_back, normal_image, normal_image_back, type_line, color_identity, set_id, rarity, cardmarket_uri, price, type, sanitized_name, set_code, layout, is_promo, can_be_commander) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19)', [carte.id, carte.name, carte.released_at, carte.card_faces[0].image_uris.small, carte.card_faces[1].image_uris.small, carte.card_faces[0].image_uris.normal, carte.card_faces[1].image_uris.normal, carte.type_line, carte.color_identity, carte.set_id, carte.rarity, carte.purchase_uris?.cardmarket, carte.prices.eur, type, carte.name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase(), carte.set, layout, promo, can_be_commander])

          } else {
            const addingCardsQuery = await client.query('INSERT INTO carte(id, name, released_at, small_image, normal_image, type_line, color_identity, set_id, rarity, cardmarket_uri, price, type, sanitized_name, set_code, layout, is_promo, can_be_commander) VALUES($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17)', [carte.id, carte.name, carte.released_at, carte.image_uris.small, carte.image_uris.normal, carte.type_line, carte.color_identity, carte.set_id, carte.rarity, carte.purchase_uris?.cardmarket, carte.prices.eur, type, carte.name.replace(/[^a-zA-Z0-9]/gim,"-").toLowerCase(), carte.set, layout, promo, can_be_commander])

          }
          total_inserted = total_inserted + 1
        } catch (err) {
          console.log(carte.uri)
          console.log(carte.layout)
          console.log(err)
          total_skipped = total_skipped + 1
        }
      } else {
        const query = 'UPDATE "carte" SET "price" = $1 WHERE "id" = $2'
        try {
          const updateQuery = await client.query(query, [carte.prices.eur, carte.id])
          total_updated = total_updated + 1
        } catch (err) {
          total_skipped = total_skipped + 1
          console.log(err)
          console.log(query)
        }
      }
    } else {
      total_skipped = total_skipped + 1
    }
  }
  console.log("Un total de " + total_inserted + " cartes ont été insérées.")
  console.log("Un total de " + total_skipped + " cartes ont été ignorées.")
  console.log("Un total de " + total_updated + " cartes ont été mises à jour.")
} catch (err) {
   console.error(err);
} finally {
   await client.end()
}