<template>
  <SVGRect :rectangle="door.position" :focused="editing" />
  <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="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="-1"
        placeholder="Tag"
        @keydown="on_keydown"
      />
      <div v-else class="is-size-1 has-text-weight-bold">
        <template v-if="door.day >= 0">{{ door.day }}</template>
      </div>
    </div>
  </foreignObject>
</template>

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

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

@Options({
  components: {
    SVGRect,
  },
  props: {
    door: Door,
    editable: {
      type: Boolean,
      default: true,
    },
  },
  emits: ["update:door"],
})
export default class extends Vue {
  private door!: Door;
  private editable!: boolean;

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

  declare $refs: {
    day_input: HTMLInputElement | null | undefined;
  };

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

  private 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 get day_num(): number {
    const result = Number(this.day_str);
    return isNaN(result) ? -1 : result;
  }

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

  private 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_num;
    }

    this.toggle_editing();
  }

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

    if (event.key === "Enter") {
      this.door.day = this.day_num;
      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: pointer;

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