<template>
  <div class="card form-group">
    <header class="card-header">
      <input class="name-input" v-model="model.name" :readonly="model.isDefaultVariant" :disabled="model.isDefaultVariant"/>
      <button type="button" class="btn btn-sm btn-outline-danger vue-delete-button" v-if="!model.isDefaultVariant" @click="deleteItem(index)">
        <span aria-hidden="true">&times;</span>
      </button>
    </header>
    <section class="card-body">
      <div class="buttons-container">
        <button type="button" class="btn btn-secondary mr-2" v-if="this.value.isDefaultVariant" @click="handleReset" :disabled="value.isUntouched">Herstel uitsnede naar standaard</button>
      </div>
      <vue-cropper
        ref="cropper"
        :view-mode="1"
        :zoomable="false"
        :auto-crop-area="1"
        :responsive="false"
        :data="cropperCrop"
        :aspect-ratio="model.fixedAspectRatio"
        :src="imageUrl"
        :img-style="{ width: '600px' }"
        :cropend="onCrop"
      />
      <input v-if="generatedUrl" type="text" class="form-control" :value="generatedUrl" readonly>
    </section>
  </div>
</template>

<script lang="ts">
import { Component, Prop, Vue, Watch, Ref } from 'vue-property-decorator';
// @ts-ignore
import VueCropper, { CropperData } from 'vue-cropperjs';

// @ts-ignore
import * as assetUtils from '../shared/asset-utils'
import _debounce from 'lodash/debounce';
import 'cropperjs/dist/cropper.css';
import AssetApi from '../api/asset-api';
import { Asset, AssetVariant, AssetVariantCrop, CenterPoint } from '../types/api';

// this is hardcoded in the backend at
// https://github.com/nederlandseloterij/Nedwin.Cms/blob/develop/src/Q42.Cms.Core.Api/Controllers/AssetApiController.cs#L116
const PREVIEW_IMAGE_WIDTH = 600;

@Component({
  components: {
    VueCropper
  }
})
export default class AssetDetailVariant extends Vue {
  @Prop({ type: Number, required: true }) readonly index!: number;
  @Prop({ type: Object, required: true }) readonly asset!: Asset;
  @Prop({ type: Object, required: true }) readonly value!: AssetVariant;
  @Prop({ type: String, required: true }) readonly imageUrl!: string;
  @Ref() readonly cropper!: any;

  generatedUrl: string | null = null;

  deleteItem(index: number) {
    this.$emit('delete', index)
  }

  handleReset() {
    if (!this.value.fixedAspectRatio) {
      return;
    }

    const crop = assetUtils.getCropForAspectRatio(this.asset, this.value.fixedAspectRatio, this.asset.centerPoint);

    this.model = {
      ...this.model,
      isUntouched: true,
      crop
    };
  }

  onCrop = _debounce(this.onCropDebounced, 300);
  onCropDebounced() {
    this.cropperCrop = this.cropper.getData();
  }

  get model(): AssetVariant {
    return this.value;
  }

  set model(value: AssetVariant) {
    this.$emit('input', value);
  }

  get cropScale() {
    return this.imageUrl.startsWith('data:image') ? 1 : this.asset.width / PREVIEW_IMAGE_WIDTH;
  }

  get cropperCrop(): CropperData | undefined {
    if (!this.value.crop) {
      return undefined;
    }

    const centerX = this.value.crop.centerPoint.x;
    const centerY = this.value.crop.centerPoint.y;
    const width = this.value.crop.width;
    const height = this.value.crop.height;

    const x = Math.min(Math.max(centerX - width / 2, 0), this.asset.width - width);
    const y = Math.min(Math.max(centerY - height / 2, 0), this.asset.height - height);

    return {
      x: x / this.cropScale,
      y: y / this.cropScale,
      width: Math.floor(this.value.crop.width / this.cropScale),
      height: Math.floor(this.value.crop.height / this.cropScale),
    } as CropperData;
  }

  set cropperCrop(newCrop: CropperData | undefined) {
    if (!newCrop) {
      return;
    }

    const centerX = newCrop.x + newCrop.width / 2;
    const centerY = newCrop.y + newCrop.height / 2;

    this.model = {
      ...this.model,
      isUntouched: false,
      crop: {
        centerPoint: {
          x: Math.floor(centerX * this.cropScale),
          y: Math.floor(centerY * this.cropScale),
        },
        width: Math.floor(newCrop.width * this.cropScale),
        height: Math.floor(newCrop.height * this.cropScale),
      }
    };
  }

  @Watch('value.crop', { immediate: true })
  async onValueCropChange(newCrop: AssetVariantCrop) {
    if (!newCrop) {
      return;
    }

    if (this.asset && this.asset.id) {
      this.generatedUrl = await AssetApi.createPublicAssetUrl(this.asset.id, null, null, newCrop);
    }

    if (this.cropper) {
      this.cropper.setData(this.cropperCrop);
    }
  }

  @Watch('asset.centerPoint', { immediate: true })
  onAssetCenterPointChange(newCenterPoint: CenterPoint) {
    if (!this.value.isUntouched) {
      return;
    }
    this.model = {
      ...this.model,
      crop: assetUtils.getCropForAspectRatio(this.asset, this.value.fixedAspectRatio, newCenterPoint)
    };
  }
}
</script>

<style lang="scss" scoped>
.card-header {
  display: flex;

  input {
    width: 100%;
    font-size: 1.25rem;
  }
}

.card-header h5 {
  flex: 1;
  margin-bottom: 0;
}

.vue-delete-button {
  margin-left: 10px;
}

.buttons-container {
  margin-bottom: 1.25rem;
}
</style>
