import FileInfoDropzone from "file_info_dropzone";

const $ = require('jquery');

describe("FileInfoDropzone", () => {
  class FakeXhr {
    constructor() {
      this.abort = jest.fn().mockImplementation(() => {})
    }
    addEventListener(eventName, callback) {
      callback()
    }
  }
  class FakeDropzone {
    constructor(element, options) {
      this.element = element
      this.options = options
      this.emitCallEventNames = []
      this.eventCallbacks = {}

      options.init.call(this)
    }

    emit(eventName, file) {
      this.emitCallEventNames.push(eventName)
    }

    on(eventName, callback) {
      this.eventCallbacks[eventName] = callback
    }

    trigger(eventName, file) {
      const myFile = file || new File([], "filename")
      this.xhr = new FakeXhr()

      this.eventCallbacks[eventName](myFile, this.xhr, null)
    }
  }

  describe("new", () => {
    it("creates a dropzone with custom settings", () => {
      document.body.innerHTML =
        `<form>` +
        `<div class="test" data-accepted-files="*">` +
        '</div>';
      '</form>';

      const dropzone = new FileInfoDropzone($(".test"), FakeDropzone);

      expect(dropzone.myDropzone.options.url).toBe("/")
      expect(dropzone.myDropzone.options.autoQueue).toBe(true)
      expect(dropzone.myDropzone.options.parallelUploads).toBe(30)
      expect(dropzone.myDropzone.options.dictDefaultMessage).toBe("Drop files here")
      expect(dropzone.myDropzone.options.acceptedFiles).toBe("*")
      expect(dropzone.myDropzone.options.maxFilesize).toBe(null)
    })
  })

  describe("when sending event triggered", () => {
    it("generates hidden fields from dropped file", () => {
      jest.spyOn(Date, 'now').mockImplementationOnce(() => 1562098199162)

      document.body.innerHTML =
        `<form>` +
        `<div class="test" data-input-name-prefix="some_model[some_associations_attributes]">` +
        '</div>';
      '</form>';

      const file = new File(["123"], "filename", {type: "image/jpg"})

      const dropzone = new FileInfoDropzone($(".test"), FakeDropzone);
      dropzone.myDropzone.trigger("sending", file)

      const generatedFilenameInput = $("input")[0];
      expect(generatedFilenameInput.type).toBe("hidden")
      expect(generatedFilenameInput.name).toBe("some_model[some_associations_attributes][1562098199162][filename]")
      expect(generatedFilenameInput.value).toBe("filename")
      const generatedContentTypeInput = $("input")[1];
      expect(generatedContentTypeInput.type).toBe("hidden")
      expect(generatedContentTypeInput.name).toBe("some_model[some_associations_attributes][1562098199162][content_type]")
      expect(generatedContentTypeInput.value).toBe("image/jpg")
      const generatedByteSizeInput = $("input")[2];
      expect(generatedByteSizeInput.type).toBe("hidden")
      expect(generatedByteSizeInput.name).toBe("some_model[some_associations_attributes][1562098199162][byte_size]")
      expect(generatedByteSizeInput.value).toBe("3")
    })

    it("generates hidden fields whose name attributes don't collide", () => {
      jest.spyOn(Date, 'now')
        .mockImplementationOnce(() => 1562098199162)
        .mockImplementationOnce(() => 1562098199169)

      document.body.innerHTML =
        `<form>` +
        `<div class="test" data-input-name-prefix="some_model[some_associations_attributes]">` +
        '</div>';
      '</form>';

      const dropzone1 = new FileInfoDropzone($(".test"), FakeDropzone);
      const dropzone2 = new FileInfoDropzone($(".test"), FakeDropzone);
      dropzone1.myDropzone.trigger("sending")
      dropzone2.myDropzone.trigger("sending")

      const firstGeneratedInput = $("input[name*='filename']")[0];
      const secondGeneratedInput = $("input[name*='filename']")[1];

      expect(firstGeneratedInput.name).toEqual("some_model[some_associations_attributes][1562098199162][filename]")
      expect(secondGeneratedInput.name).toEqual("some_model[some_associations_attributes][1562098199169][filename]")
    })

    it("cancels dropzone remote request", () => {
      document.body.innerHTML =
        `<form>` +
        `<div class="test">` +
        '</div>';
      '</form>';

      const dropzone = new FileInfoDropzone($(".test"), FakeDropzone);
      dropzone.myDropzone.trigger("sending")

      expect(dropzone.myDropzone.xhr.abort).toHaveBeenCalled()
    })

    it("emits success and complete events to dropzone", () => {
      document.body.innerHTML =
        `<form>` +
        `<div class="test">` +
        '</div>';
      '</form>';

      const dropzone = new FileInfoDropzone($(".test"), FakeDropzone);
      dropzone.myDropzone.trigger("sending")

      expect(dropzone.myDropzone.emitCallEventNames).toEqual(["success", "complete"])
    })
  })

  describe("when adding existing files", () => {
    it("emits addedfile and complete events for each existing file", () => {
      const data = [{"name":"filename","size":123,"type":"image/jpg"}]

      document.body.innerHTML =
        `<form>` +
        `<div class="test" data-existing-files='${JSON.stringify(data)}'>` +
        '</div>' +
      '</form>';

      const dropzone = new FileInfoDropzone($(".test"), FakeDropzone);

      expect(dropzone.myDropzone.emitCallEventNames).toEqual(["addedfile", "complete"])
    })
  })
})
