<template>
  <SVGRect
    :rectangle="door.position"
    :variant="editing ? 'success' : 'primary'"
  />
  <foreignObject
    :x="Math.round(parent_aspect_ratio * door.position.left)"
    :y="door.position.top"
    :width="Math.round(parent_aspect_ratio * door.position.width)"
    :height="door.position.height"
    :style="`transform: scaleX(${1 / parent_aspect_ratio})`"
  >
    <div
      xmlns="http://www.w3.org/1999/xhtml"
      class="px-4 is-flex is-align-items-center is-justify-content-center"
      @click.left="on_click"
    >
      <input
        v-if="editing"
        v-model="day_str"
        ref="day_input"
        class="input is-large"
        type="number"
        :min="MIN_DAY"
        placeholder="Tag"
        @keydown="on_keydown"
      />
      <div v-else class="is-size-1 has-text-weight-bold has-text-danger">
        {{ door.day > 0 ? door.day : "*" }}
      </div>
    </div>
  </foreignObject>
</template>

<script lang="ts">
import { Door } from "@/lib/door";
import { Options, Vue } from "vue-class-component";

import SVGRect from "../calendar/SVGRect.vue";

@Options({
  components: {
    SVGRect,
  },
  props: {
    door: Door,
  },
  emits: ["update:door"],
})
export default class extends Vue {
  public door!: Door;
  public readonly MIN_DAY = Door.MIN_DAY;

  public day_str = "";
  public editing = false;
  private refreshKey = 0;

  declare $refs: {
    day_input: HTMLInputElement | unknown;
  };

  private refresh() {
    window.setTimeout(() => {
      // don't loop endlessly
      if (this.refreshKey < 10000) {
        this.refreshKey++;
      }
    }, 100);
  }

  public get parent_aspect_ratio(): number {
    this.refreshKey; // read it just to force recompute on change

    if (!(this.$el instanceof Text) || this.$el.parentElement === null) {
      this.refresh();
      return 1;
    }

    const parent = this.$el.parentElement;
    const result = parent.clientWidth / parent.clientHeight;

    // force recompute for suspicious results
    if (result === 0 || result === Infinity) {
      this.refresh();
      return 1;
    }

    return result;
  }

  private toggle_editing() {
    this.day_str = String(this.door.day);
    this.editing = !this.editing;
  }

  public on_click(event: MouseEvent) {
    if (event.target === null || !(event.target instanceof HTMLDivElement)) {
      return;
    }

    if (!this.editing) {
      const day_input_focus = () => {
        if (this.$refs.day_input instanceof HTMLInputElement) {
          this.$refs.day_input.select();
          return;
        }

        this.$nextTick(day_input_focus);
      };
      day_input_focus();
    } else {
      this.door.day = this.day_str;
    }

    this.toggle_editing();
  }

  public on_keydown(event: KeyboardEvent) {
    if (!this.editing) {
      return;
    }

    if (event.key === "Enter") {
      this.door.day = this.day_str;
      this.toggle_editing();
    } else if (event.key === "Delete") {
      this.door.day = -1;
      this.toggle_editing();
    } else if (event.key === "Escape") {
      this.toggle_editing();
    }
  }

  public beforeUnmount() {
    this.$emit("update:door", this.door);
  }
}
</script>

<style lang="scss" scoped>
foreignObject {
  cursor: text;

  > div {
    height: inherit;
  }
}
</style>
