<template>
  <div class="combat-layout">
    <div @wheel="horizWheelLeft" class="statblock-row left-stats">
      <Statblock @selected="scrollParentTo($event)" @select="doSelectLeft(combatant, $event)" class="left-stats" :data-ally="combatant.side === encounter.currentMove.side" :data-destroyed="combatant.destroyed" :data-current-turn="encounter.currentMove === combatant" :data-active="combatant === left && combatant !== encounter.currentMove" :data-active-ally="combatant === right" :data-eaten="combatant.containedIn !== null" :data-dead="combatant.vigors.Health <= 0" v-for="(combatant, index) in combatants.filter(c => c.side == Side.Heroes).slice().reverse()" v-bind:key="'left-stat-' + index" :subject="combatant" :initiative="encounter.initiatives.get(combatant)" />
      <div class="spacer"></div>
    </div>
    <div @wheel="horizWheelRight" class="statblock-row right-stats">
      <Statblock @selected="scrollParentTo($event)" @select="doSelectRight(combatant, $event)" class="right-stats" :data-ally="combatant.side === encounter.currentMove.side" :data-destroyed="combatant.destroyed" :data-current-turn="encounter.currentMove === combatant" :data-active="combatant === right && combatant !== encounter.currentMove" :data-active-ally="combatant === left" :data-eaten="combatant.containedIn !== null" :data-dead="combatant.vigors.Health <= 0" v-for="(combatant, index) in combatants.filter(c => c.side == Side.Monsters)" v-bind:key="'right-stat-' + index" :subject="combatant" :initiative="encounter.initiatives.get(combatant)" />
      <div class="spacer"></div>
    </div>
    <div class="statblock-separator statblock-separator-left"></div>
    <div class="statblock-separator statblock-separator-center"></div>
    <div class="statblock-separator statblock-separator-right"></div>
    <div class="log">
      <div class="log-entry log-filler"></div>
    </div>
    <div class="left-fader">

    </div>
    <div class="left-actions">
      <div v-if="encounter.currentMove === left" class="vert-display">
        <i class="action-label fas fa-users" v-if="left.validGroupActions(combatants).length > 0"></i>
        <ActionButton @described="described" @executed="executedLeft" v-for="(action, index) in left.validGroupActions(combatants)" :key="'left-' + action.name + '-' + index" :action="action" :user="left" :target="right" :combatants="combatants" />
        <i class="action-label fas fa-user-friends" v-if="left.validActions(right).length > 0"></i>
        <ActionButton @described="described" @executed="executedLeft" v-for="(action, index) in left.validActions(right)" :key="'left-' + action.name + '-' + index" :action="action" :user="left" :target="right" :combatants="combatants" />
        <i class="action-label fas fa-user" v-if="left.validActions(left).length > 0"></i>
        <ActionButton @described="described" @executed="executedLeft" v-for="(action, index) in left.validActions(left)" :key="'left-' + action.name + '-' + index" :action="action" :user="left" :target="left" :combatants="combatants" />
      </div>
      <div>{{actionDescription}}</div>
    </div>
    <div class="right-fader">

    </div>
    <div class="right-actions">
      <div v-if="encounter.currentMove === right" class="vert-display">
        <i class="action-label fas fa-users" v-if="right.validGroupActions(combatants).length > 0"></i>
        <ActionButton @described="described" @executed="executedRight" v-for="(action, index) in right.validGroupActions(combatants)" :key="'right-' + action.name + '-' + index" :action="action" :user="right" :target="left" :combatants="combatants" />
        <i class="action-label fas fa-user-friends" v-if="right.validActions(left).length > 0"></i>
        <ActionButton @described="described" @executed="executedRight" v-for="(action, index) in right.validActions(left)" :key="'right-' + action.name + '-' + index" :action="action" :user="right" :target="left" :combatants="combatants" />
        <i class="action-label fas fa-user" v-if="right.validActions(right).length > 0"></i>
        <ActionButton @described="described" @executed="executedRight" v-for="(action, index) in right.validActions(right)" :key="'right-' + action.name + '-' + index" :action="action" :user="right" :target="right" :combatants="combatants" />
      </div>
    </div>
    <div v-if="encounter.winner === null" class="action-description">
    </div>
    <button @click="$emit('leaveCombat')" v-if="encounter.winner !== null" class="exit-combat">
      Exit Combat
    </button>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch, Emit } from 'vue-property-decorator'
import { Creature } from '@/game/creature'
import { POV } from '@/game/language'
import { LogEntry, LogLine } from '@/game/interface'
import Statblock from './Statblock.vue'
import ActionButton from './ActionButton.vue'
import { Side, Encounter } from '@/game/combat'

@Component(
  {
    components: { Statblock, ActionButton },
    data () {
      return {
        left: null,
        right: null,
        combatants: null
      }
    }
  }
)

export default class Combat extends Vue {
  @Prop()
  encounter!: Encounter

  Side = Side

  actionDescription = ''

  @Emit("described")
  described (entry: LogEntry) {
    const actionDesc = this.$el.querySelector(".action-description")

    if (actionDesc !== null) {
      const holder = document.createElement("div")
      entry.render().forEach(element => {
        holder.appendChild(element)
      })
      actionDesc.innerHTML = ''
      actionDesc.appendChild(holder)
    }
  }

  @Emit("executedLeft")
  executedLeft (entry: LogEntry) {
    this.writeLog(entry, "left")

    this.writeLog(this.encounter.nextMove(), "center")
    this.pickNext()
  }

  // TODO these need to render on the correct side

  @Emit("executedRight")
  executedRight (entry: LogEntry) {
    this.writeLog(entry, "right")

    this.writeLog(this.encounter.nextMove(), "center")
    this.pickNext()
  }

  writeLog (entry: LogEntry, side = "") {
    const log = this.$el.querySelector(".log")
    if (log !== null) {
      const elements = entry.render()

      if (elements.length > 0) {
        const before = log.querySelector("div.log-entry") as HTMLElement|null

        const holder = document.createElement("div")
        holder.classList.add("log-entry")
        entry.render().forEach(element => {
          holder.appendChild(element)
        })

        if (side !== "") {
          holder.classList.add(side + "-move")
        }

        const hline = document.createElement("div")
        hline.classList.add("log-separator")
        if (side !== "") {
          hline.classList.add("log-separator-" + side)
        }
        log.insertBefore(hline, before)
        log.insertBefore(holder, hline)

        // TODO this behaves a bit inconsistent -- sometimes it jerks and doesn't scroll to the top
        if (log.scrollTop === 0 && before !== null) {
          log.scrollTo({ top: before.offsetTop, left: 0 })
        }

        log.scrollTo({ top: 0, left: 0, behavior: "smooth" })
      }
    }
  }

  pickNext () {
    // Did one side win?

    if (this.encounter.winner !== null) {
      this.writeLog(
        new LogLine(
          `game o-vore lmaoooooooo`
        ),
        "center"
      )
    } else {
      if (this.encounter.currentMove.side === Side.Heroes) {
        this.$data.left = this.encounter.currentMove

        if (this.encounter.currentMove.containedIn !== null) {
          this.$data.right = this.encounter.currentMove.containedIn.owner
        }
      } else if (this.encounter.currentMove.side === Side.Monsters) {
        this.$data.right = this.encounter.currentMove

        if (this.encounter.currentMove.containedIn !== null) {
          this.$data.left = this.encounter.currentMove.containedIn.owner
        }
      }
      // scroll to the newly selected creature
      this.$nextTick(() => {
        const creature: HTMLElement|null = this.$el.querySelector("[data-current-turn]")
        if (creature !== null) {
          this.scrollParentTo(creature)
        }
        const target: HTMLElement|null = this.$el.querySelector("[data-active]")
        if (target !== null) {
          this.scrollParentTo(target)
        }
      })
    }
  }

  selectable (creature: Creature): boolean {
    return !creature.destroyed && this.encounter.currentMove !== creature
  }

  doScroll (target: HTMLElement, speed: number, t: number) {
    if (t <= 0.25) {
      target.scrollBy(speed / 20 - speed / 20 * Math.abs(0.125 - t) * 8, 0)
      setTimeout(() => this.doScroll(target, speed, t + 1 / 60), 1000 / 60)
    }
  }

  horizWheelLeft (event: MouseWheelEvent) {
    const target = this.$el.querySelector(".left-stats") as HTMLElement

    if (target !== null) {
      this.doScroll(target, event.deltaY > 0 ? 200 : -200, 0)
    }
  }

  horizWheelRight (event: MouseWheelEvent) {
    const target = this.$el.querySelector(".right-stats") as HTMLElement

    if (target !== null) {
      this.doScroll(target, event.deltaY > 0 ? 200 : -200, 0)
    }
  }

  scrollParentTo (element: HTMLElement): void {
    if (element.parentElement !== null) {
      const pos = (element.offsetLeft - element.parentElement.offsetLeft)
      const width = element.getBoundingClientRect().width / 2
      const offset = element.parentElement.getBoundingClientRect().width / 2

      element.parentElement.scrollTo({ left: pos + width - offset, behavior: "smooth" })
    }
  }

  doSelectLeft (combatant: Creature, element: HTMLElement) {
    if (this.selectable(combatant)) {
      if (combatant.side !== this.$props.encounter.currentMove.side) {
        this.$data.left = combatant
      } else {
        this.$data.right = combatant
      }
    }

    this.scrollParentTo(element)
  }

  doSelectRight (combatant: Creature, element: HTMLElement) {
    if (this.selectable(combatant)) {
      if (combatant.side !== this.$props.encounter.currentMove.side) {
        this.$data.right = combatant
      } else {
        this.$data.left = combatant
      }
    }

    this.scrollParentTo(element)
  }

  created () {
    this.$data.left = this.encounter.combatants.filter(x => x.side === Side.Heroes)[0]
    this.$data.right = this.encounter.combatants.filter(x => x.side === Side.Monsters)[0]
    this.$data.combatants = this.encounter.combatants
  }

  mounted () {
    const leftStats = this.$el.querySelector(".left-stats")

    if (leftStats !== null) {
      leftStats.scrollTo(leftStats.getBoundingClientRect().width * 2, 0)
    }

    this.pickNext()
  }
}
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>

.spacer {
  flex: 1 0;
  min-width: 2px;
  min-height: 100%;
}

.exit-combat {
  grid-area: 2 / main-col-start / main-row-start / main-col-end;
  width: 100%;
  padding: 4pt;
  flex: 0 1;
  background: #333;
  border-color: #666;
  border-style: outset;
  user-select: none;
  color: #eee;
  font-size: 36px;
}

.combat-layout {
  position: relative;
  display: grid;
  grid-template-rows: fit-content(50%) 10% [main-row-start] 1fr 20% [main-row-end] ;
  grid-template-columns: 1fr [main-col-start] fit-content(25%) fit-content(25%) [main-col-end] 1fr;
  width: 100%;
  height: 100%;
  overflow-x: hidden;
  overflow-y: hidden;
  margin: auto;
}

.log {
  position: relative;
  grid-area: main-row-start / main-col-start / main-row-end / main-col-end;
  overflow-y: scroll;
  overflow-x: hidden;
  font-size: 1rem;
  width: 100%;
  max-height: 100%;
  width: 70vw;
  max-width: 1000px;
  align-self: flex-start;
  height: 100%;
}

.log-filler {
  height: 100%;
}

.left-stats,
.right-stats {
  display: flex;
}

.left-stats {
  flex-direction: row;
}

.right-stats {
  flex-direction: row;
}

.left-stats {
  grid-area: 1 / 1 / 2 / 3
}

.right-stats {
  grid-area: 1 / 3 / 2 / 5;
}

.statblock-separator-left {
  grid-area: 1 / 1 / 2 / 1;
}

.statblock-separator-center {
  grid-area: 1 / 3 / 2 / 3;
}

.statblock-separator-right {
  grid-area: 1 / 5 / 2 / 5;
}

.statblock-separator {
  position: absolute;
  width: 10px;
  height: 100%;
  transform: translate(-5px, 0);
  background: linear-gradient(90deg, transparent, #111 3px, #111  7px, transparent 10px);
}

.statblock-row {
  overflow-x: scroll;
  overflow-y: auto;
}

.left-fader {
  grid-area: 2 / 1 / 4 / 2;
}

.right-fader {
  grid-area: 2 / 4 / 4 / 5;
}

.left-fader,
.right-fader {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to bottom, #111, #00000000 10%, #00000000 90%, #111 100%);
  height: 100%;
  width: 100%;
}

.left-actions {
  grid-area: 2 / 1 / 4 / 2;
}

.right-actions {
  grid-area: 2 / 4 / 4 / 5;
}

.left-actions > .vert-display {
  align-items: flex-end;
}

.right-actions > .vert-display {
  align-items: flex-start;
}

.left-actions,
.right-actions {
  overflow-y: hidden;
  display: flex;
  flex-direction: column;
  height: 100%;
  width: 100%;
}

.action-description {
  grid-area: 2 / main-col-start / main-row-start / main-col-end;
  padding: 8pt;
  text-align: center;
  font-size: 16px;
  max-width: 1000px;
}

h3 {
  margin: 40px 0 0;
}
ul {
  list-style-type: none;
  padding: 0;
}
li {
  display: inline-block;
  margin: 0 10px;
}
a {
  color: #42b983;
}
.horiz-display {
  display: flex;
  justify-content: center;
}

.vert-display {
  display: flex;
  flex-direction: column;
  align-items: center;
  flex-wrap: nowrap;
  justify-content: start;
  height: 100%;
  width: 100%;
  overflow-y: auto;
  padding: 64px 0 64px;
}

.action-label {
  font-size: 200%;
  max-width: 300px;
  width: 100%;
}
</style>

<style>

.log-damage {
  font-weight: bold;
}

.damage-instance {
  white-space: nowrap;
}

.log > div.log-entry {
  position: relative;
  color: #888;
  padding-top: 4pt;
  padding-bottom: 4pt;
}

div.left-move,
div.right-move {
  color: #888;
}

div.left-move {
  text-align: start;
  margin-right: 25%;
  margin-left: 2%;
}

div.right-move {
  text-align: end;
  margin-left: 25%;
  margin-right: 2%;
}

.log img {
  width: 75%;
}

.log > div.left-move:nth-child(7) {
  color: #898;
}

.log > div.left-move:nth-child(6) {
  color: #8a8;
}

.log > div.left-move:nth-child(5) {
  color: #8b8;
}

.log > div.left-move:nth-child(4) {
  color: #8c8;
}

.log > div.left-move:nth-child(3) {
  color: #8d8;
}

.log > div.left-move:nth-child(2) {
  color: #8e8;
}

.log > div.left-move:nth-child(1) {
  color: #8f8;
}

.log > div.right-move:nth-child(7) {
  color: #988;
}

.log > div.right-move:nth-child(6) {
  color: #a88;
}

.log > div.right-move:nth-child(5) {
  color: #b88;
}

.log > div.right-move:nth-child(4) {
  color: #c88;
}

.log > div.right-move:nth-child(3) {
  color: #d88;
}

.log > div.right-move:nth-child(2) {
  color: #e88;
}

.log > div.right-move:nth-child(1) {
  color: #f88;
}

.left-selector,
.right-selector {
  display: flex;
  flex-wrap: wrap;
}

.combatant-picker {
  flex: 1 1;
}

.log-separator {
  animation: log-keyframes 0.5s;
  height: 4px;
  background: linear-gradient(90deg, transparent, #444 10%, #444 90%, transparent 100%);
}

.log-separator-left {
  margin: 4pt auto 4pt 0;
}

.log-separator-center {
  margin: 4pt auto 4pt;
}

.log-separator-right {
  margin: 4pt 0 4pt auto;
}

@keyframes log-keyframes {
  from {
    width: 0%;
  }

  to {
    width: 100%;
  }
}

.left-move {
  animation: left-fly-in 1s;
}

.right-move {
  animation: right-fly-in 1s;
}

.center-move {
  animation: center-fly-in 1s;
}

@keyframes left-fly-in {
  0% {
    opacity: 0;
    transform: translate(-50px, 0);
  }

  50% {
    transform: translate(0, 0);
  }

  100% {
    opacity: 1;
  }
}

@keyframes right-fly-in {
  0% {
    opacity: 0;
    transform: translate(50px, 0);
  }

  50% {
    transform: translate(0, 0);
  }

  100% {
    opacity: 1;
  }
}

@keyframes center-fly-in {
  0% {
    opacity: 0;
  }

  100% {
    opacity: 1;
  }
}
</style>
