'use strict'

import CardsDB from '@/plugins/ffdecks'

export default class {
  constructor(id) {
    this.id = id
    this.name = ''
    this.note = ''
    this.cards = []
  }

  populate() {
    for (let card of this.cards) {
      card.dbentry = CardsDB[card.serial]
    }
  }

  from_object(obj) {
    if (obj) {
      this.name = obj.name
      this.note = obj.note
      this.cards = obj.cards
    }
  }

  plainObject() {
    let plainCards = []
    for (let card of this.cards) {
      plainCards.push({
        serial: card.serial,
        count: card.count
      })
    }

    return {
      name: this.name,
      note: this.note,
      cards: plainCards
    }
  }

  from_deckList(str) {
    // select all lines containing card serial numbers
    let cardLinesRE = /^.*\b\d+-0*\d{1,3}[A-Z]?\b.*$/gm
    let cardLines = str.match(cardLinesRE)
    let cardCounts = {}

    if (cardLines) {
      for (let cardLine of cardLines) {
        // extract serial (guaranteed to be in here!)
        let serialRE = /\b(\d+)-0*(\d{1,3})[A-Z]?\b/i
        let serial = serialRE.exec(cardLine)
        // force format 'x-xxx'
        serial = `${serial[1]}-${serial[2].padStart(3, '0')}`

        // strip out serial number
        cardLine = cardLine.replace(serialRE, '')

        let countREs = [
          // prioritize a count with "times" symbol *, x, ×
          /\b([0-9]+)(?:[*×]|[x]\b)/,
          /(?:[*×]|\b[x])([0-9]+)\b/,
          // next priority: count with whitespace
          /\s+([0-9]+)\s+/,
          /\s+([0-9]+)\b/,
          /\b([0-9]+)\s+/,
          // least priority: any simple number
          /\b([0-9]+)\b/
        ]

        // fallback value
        let count = 1
        for (let countRE of countREs) {
          let data = countRE.exec(cardLine)

          if (data) {
            count = Number(data[1])
            break
          }
        }

        // count copies
        if (!cardCounts[serial]) {
          cardCounts[serial] = 0
        }
        cardCounts[serial] += count
      }
    }

    // push card data into deck
    this.cards = []
    for (let serial in cardCounts) {
      this.cards.push({
        serial: serial,
        count: cardCounts[serial]
      })
    }

    // strip out lines with serial numbers
    str = str.replace(cardLinesRE, '')
    // then strip out anything after the first empty line
    str = str.replace(/^[\s]*$[^]*/m, '')

    // select the line containing 'deck name:'
    // and its successor (ffdecks format)
    let metaRE = /^Deck Name: (.+)$[\s]*?^(.+)$/m
    let metaData = metaRE.exec(str)

    // fallback
    this.name = 'Unnamed Deck'
    this.note = ''

    if (!metaData) {
      // use lax format: <anything>:[deck name][newline][note]
      metaRE = /[^]*?:(.+)$[\s]*?^([^]*)/m
      metaData = metaRE.exec(str)
    }

    // look again, I am not an else!
    if (metaData) {
      // extract matches
      this.name = metaData[1].trim()
      this.note = metaData[2].trim()
    }
  }

  parts() {
    let retval = ['Forwards', 'Backups', 'Summons, Monsters & more'].map(
      item => ({
        heading: item,
        cards: [],
        count: 0
      })
    )

    for (let card of this.cards) {
      let target
      switch (card.dbentry.type) {
        case 'Forward':
          target = 0
          break
        case 'Backup':
          target = 1
          break
        default:
          target = 2
          break
      }
      retval[target].cards.push(card)
      retval[target].count += card.count
    }

    for (let part of retval) {
      part.cards.sort(
        (card_l, card_r) => card_l.dbentry.cost - card_r.dbentry.cost
      )
    }

    return retval
  }

  deckList() {
    // empty deck is empty
    if (this.count() == 0) return ''

    let lines = []

    // begin with deck name and note
    lines.push('Deck Name: ' + this.name)
    lines.push(this.note)
    lines.push('')

    // list each deck part
    for (let part of this.parts()) {
      lines.push(`${part.heading} (${part.count}):`)

      for (let card of part.cards)
        lines.push(`${card.count}x ${card.serial} "${card.dbentry.name}"`)

      lines.push('')
    }

    return lines.join('\n')
  }

  count() {
    return this.cards.reduce((total, card) => total + card.count, 0)
  }
}
