<template>
  <section class="deckbuilder">
    <section class="cardlist">
      <section class="filters">
        <div class="row">
          <b-input
            @input="textChanged"
            v-model="nameFilter"
            placeholder="Search name"
          ></b-input>
          <div class="colorfilter" v-for="color in colors" :key="color">
            <img
              @click="toggleFilter(elementFilters, color)"
              :class="filterIconClass(elementFilters, color)"
              :src="elementIconURL(color)"
            />
          </div>
          <div class="divider" />
          <div class="typefilter" v-for="type in types" :key="type">
            <img
              @click="toggleFilter(typeFilters, type)"
              :class="filterIconClass(typeFilters, type)"
              :src="typeIconURL(type)"
            />
          </div>
        </div>
        <div class="row">
          <b-input
            @input="textChanged"
            v-model="ruleFilter"
            placeholder="Search rule text"
          ></b-input>
          <div class="setfilter" v-for="set in sets" :key="set">
            <img
              @click="toggleFilter(setFilters, set)"
              :class="filterIconClass(setFilters, set)"
              :src="setIconURL(set)"
            />
          </div>
        </div>
      </section>
      <section class="cards">
        <div @click="prevPage" :class="canGoPrev ? 'prev' : 'prev unavailable'">
          <img src="../assets/images/deckbuilder/navarrow.svg" />
        </div>
        <CardPicker
          @picked="cardPicked"
          :columns="columns"
          :rows="rows"
          :cards="currentPage"
        />
        <div @click="nextPage" :class="canGoNext ? 'next' : 'next unavailable'">
          <img src="../assets/images/deckbuilder/navarrow.svg" />
        </div>
      </section>
    </section>
    <section class="decklist">
      <header>
        <h1>{{ deckname }}</h1>
        <nav class="buttons">
          <b-button @click="exportToPonyhead" size="is-small deck-btn"
            >Ponyhead</b-button
          >
        </nav>
      </header>
      <DeckList :cards="decklist" @removed="cardRemoved" />
    </section>
  </section>
</template>

<style lang="scss" scoped>
@import "@/assets/scss/_variables.scss";

.deckbuilder {
  background: url("../assets/images/backgrounds/deckbuilderbg.webp") center;
  background-repeat: no-repeat;
  background-size: cover;
  height: 100vh;
  display: grid;
  grid-template-columns: 3fr minmax(250px, 1fr);
}

.cardlist {
  display: grid;
  grid-column: 1;
  grid-template-rows: 110px 1fr;
}

.filters {
  display: flex;
  flex-direction: column;
  padding: 5px;
  .row {
    flex: 1;
    display: flex;
    align-items: center;
    * {
      margin: 5px;
    }
  }
}

.cards {
  display: grid;
  grid-template-columns: 5% 1fr 5%;
}

.decklist {
  padding: 10px;
  padding-top: 15px;
  grid-column: 2;
  header {
    padding-left: 1rem;
    color: $primary-text;
    font-family: $fantasy;
    h1 {
      font-size: 20pt;
      font-weight: 700;
      margin-bottom: 5px;
    }
  }
}

.colorfilter,
.setfilter,
.typefilter {
  cursor: pointer;
  img {
    opacity: 0.4;
    &:hover {
      opacity: 0.7;
    }
    &.selected {
      opacity: 1;
    }
  }
}

.colorfilter {
  width: 42px;
  height: 42px;
}

.setfilter {
  width: 32px;
  height: 32px;
}

.typefilter {
  width: 42px;
  height: 42px;
}

.prev,
.next {
  opacity: 0.5;
  display: flex;
  cursor: pointer;
  &:hover {
    opacity: 0.9;
  }
  &.unavailable {
    opacity: 0.1;
    cursor: not-allowed;
  }
}

.next img {
  transform: scaleX(-1);
}

.divider {
  width: 10px;
  height: 10px;
}

.deck-btn {
  padding: 0 10px;
  padding-bottom: 2px;
}
</style>

<script lang="ts">
import { Component, Vue } from "vue-property-decorator";
import DeckList from "@/components/DeckBuilder/DeckList.vue";
import CardPicker from "@/components/DeckBuilder/CardPicker.vue";
import {
  Card,
  CardFilter,
  CardSlot,
  getCards,
  allSets,
  cardFullName,
  createPonyheadURL,
  multiElemStr,
  typeIndex,
  rarityIndex,
  colorNames,
  typeNames,
  cardLimit
} from "@/mlpccg";

// Sort function for sorting cards
function sortByColor(a: Card, b: Card) {
  const typeA = typeIndex(a.Type);
  const typeB = typeIndex(b.Type);
  if (typeA != typeB) {
    return typeA - typeB;
  }
  // Same types, filter by primary element
  switch (a.Type) {
    case "Friend":
    case "Mane Character":
      {
        const elemA = multiElemStr(a.Element);
        const elemB = multiElemStr(b.Element);
        if (elemA > elemB) {
          return 1;
        }
        if (elemB > elemA) {
          return -1;
        }
      }
      break;
    case "Problem":
      if (a.ProblemRequirement && b.ProblemRequirement) {
        const preqA = multiElemStr(Object.keys(a.ProblemRequirement));
        const preqB = multiElemStr(Object.keys(b.ProblemRequirement));
        if (preqA > preqB) {
          return 1;
        }
        if (preqB > preqA) {
          return -1;
        }
      }
      break;
    case "Event":
    case "Resource":
      if (a.Requirement && b.Requirement) {
        const reqA = multiElemStr(Object.keys(a.Requirement));
        const reqB = multiElemStr(Object.keys(b.Requirement));
        if (reqA > reqB) {
          return 1;
        }
        if (reqB > reqA) {
          return -1;
        }
      }
      break;
  }
  // Filter by power
  if (a.Power && b.Power) {
    if (a.Power != b.Power) {
      return a.Power - b.Power;
    }
  }

  // Filter by Rarity (not the pony)
  const rarityA = rarityIndex(a.Rarity);
  const rarityB = rarityIndex(b.Rarity);
  if (rarityA != rarityB) {
    return rarityA - rarityB;
  }

  const nameA = cardFullName(a);
  const nameB = cardFullName(b);
  if (nameA > nameB) {
    return 1;
  }
  if (nameB > nameA) {
    return -1;
  }
  return 0;
}

@Component({
  components: {
    DeckList,
    CardPicker
  }
})
export default class DeckBuilder extends Vue {
  // Picked/filtered cards
  private decklist!: CardSlot[];
  private filtered!: Card[];

  // Names
  private colors!: string[];
  private sets!: string[];
  private types!: string[];

  // Card picker size
  private rows!: number;
  private columns!: number;

  // User Filters
  private nameFilter!: string;
  private ruleFilter!: string;
  private setFilters!: string[];
  private elementFilters!: string[];
  private typeFilters!: string[];

  // Decklist options
  private deckname!: string;

  // Navigation
  private offset!: number;

  private data() {
    return {
      decklist: [],
      filtered: [],
      offset: 0,
      rows: 2,
      columns: 5,
      nameFilter: "",
      ruleFilter: "",
      setFilters: [],
      elementFilters: [],
      typeFilters: [],
      colors: colorNames,
      sets: allSets.slice(0, -1),
      types: typeNames,
      deckname: "Unnamed deck"
    };
  }

  private mounted() {
    this.applyFilters();
  }

  private async applyFilters() {
    let filters: CardFilter = {};
    if (this.setFilters.length > 0) {
      filters.Sets = this.setFilters;
    }
    if (this.elementFilters.length > 0) {
      filters.Elements = this.elementFilters;
    }
    if (this.typeFilters.length > 0) {
      filters.Types = this.typeFilters;
    }
    if (this.nameFilter.length > 0) {
      filters.Name = this.nameFilter;
    }
    if (this.ruleFilter.length > 0) {
      filters.Rules = this.ruleFilter;
    }
    const filtered = await getCards(filters);
    this.filtered = filtered.sort(sortByColor);
    this.offset = 0;
  }

  private get itemsPerPage() {
    return this.columns * this.rows;
  }

  private get currentPage(): CardSlot[] {
    return this.filtered
      .slice(this.offset, this.offset + this.itemsPerPage)
      .map(card => {
        const res = this.decklist.find(c => c.data.ID == card.ID);
        if (res) {
          return res;
        }
        return {
          data: card,
          limit: cardLimit(card.Type),
          howmany: 0
        };
      });
  }

  private elementIconURL(element: string): string {
    return require(`../assets/images/elements/${element.toLowerCase()}.webp`);
  }

  private setIconURL(set: string): string {
    return require(`../assets/images/sets/${set.toUpperCase()}.webp`);
  }

  private typeIconURL(type: string): string {
    let urltype = type.toLowerCase();
    if (urltype == "mane character") {
      urltype = "mane-char";
    }
    return require(`../assets/images/cardtypes/${urltype}.webp`);
  }

  private filterIconClass(filter: string[], key: string) {
    return {
      selected: filter.includes(key)
    };
  }

  private toggleFilter(filter: string[], key: string) {
    const idx = filter.indexOf(key);
    if (idx >= 0) {
      filter.splice(idx, 1);
    } else {
      filter.push(key);
    }
    this.applyFilters();
  }

  private textChanged() {
    this.applyFilters();
  }

  private get canGoPrev(): boolean {
    return this.offset > 0;
  }

  private get canGoNext(): boolean {
    return this.offset + this.itemsPerPage < this.filtered.length;
  }

  private prevPage() {
    if (!this.canGoPrev) {
      return;
    }
    this.offset = Math.max(0, this.offset - this.itemsPerPage);
  }

  private nextPage() {
    if (!this.canGoNext) {
      return;
    }
    this.offset = Math.min(
      this.filtered.length - this.itemsPerPage,
      this.offset + this.itemsPerPage
    );
  }

  private cardPicked(card: Card) {
    // Check if card is already in
    const idx = this.decklist.findIndex(c => c.data.ID == card.ID);
    if (idx >= 0) {
      const deckitem = this.decklist[idx];
      deckitem.howmany += 1;
      Vue.set(this.decklist, idx, deckitem);
    } else {
      this.decklist.push({
        data: card,
        limit: cardLimit(card.Type),
        howmany: 1
      });
    }
  }

  private exportToPonyhead() {
    const url = createPonyheadURL(this.decklist.map(c => c.data));
    window.open(url, "_blank");
  }

  private cardRemoved(card: CardSlot) {
    const idx = this.decklist.findIndex(c => c.data.ID == card.data.ID);
    if (idx < 0) {
      throw new Error("Removing card that isn't in the deck?");
    }
    const deckitem = this.decklist[idx];
    deckitem.howmany -= 1;
    if (deckitem.howmany <= 0) {
      this.decklist.splice(idx, 1);
    } else {
      Vue.set(this.decklist, idx, deckitem);
    }
  }
}
</script>
