/* eslint-env jest */

import React from "react";
import "@testing-library/jest-dom/extend-expect";
import { render, cleanup, fireEvent } from "@testing-library/react";
import Provider from "@src/components/Context/Provider";

import FileComponent from "../File";

afterEach(cleanup);

test("Smoke", async () => {
  const { queryAllByTestId } = render(
    <Provider>
      <FileComponent themed />
    </Provider>,
  );
  expect(queryAllByTestId("file").length).toBe(1);
});

test("Custom class", async () => {
  const { getByTestId } = render(
    <Provider>
      <FileComponent themed className="test" />
    </Provider>,
  );
  expect(getByTestId("file")).toHaveClass("test");
});

test("On change test", async () => {
  const mockFn = jest.fn();
  window.URL.createObjectURL = function() {};

  const file = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  const { getByTestId } = render(
    <Provider>
      <FileComponent themed prefixClassName="test" />
    </Provider>,
  );
  const input = document.getElementsByClassName("test-input")[0];
  input.onchange = mockFn;

  Object.defineProperty(input, "files", {
    value: [file],
  });

  fireEvent.change(input);
  expect(mockFn).toHaveBeenCalled();
});

test("File size", async () => {
  const error = jest.fn();
  window.URL.createObjectURL = function() {};
  const file = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  const { rerender } = render(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        maxFileSize={0.000001}
        onError={error}
      />
    </Provider>,
  );
  const input = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(input, "files", {
    value: [file],
  });
  fireEvent.change(input);

  rerender(
    <Provider>
      <FileComponent
        themed
        type="file"
        prefixClassName="test"
        maxFileSize={0.000001}
        onError={error}
      />
    </Provider>,
  );
  const input_file = document.getElementsByClassName("test-input")[0];
  Object.defineProperty(input_file, "file", {
    value: [file],
  });
  fireEvent.change(input_file);
  expect(error).toHaveBeenCalledTimes(2);
});

test("Multiple test", async () => {
  const { getByTestId } = render(
    <Provider>
      <FileComponent themed prefixClassName="test" multiple={true} />
    </Provider>,
  );
  const input = document.getElementsByClassName("test-input")[0];
  expect(input.multiple).toEqual(true);
});

//Extenstion Tests

//#region Single File Upload Tests
test("Single - Image Extension Test", async () => {
  const error = jest.fn();
  window.URL.createObjectURL = function() {};

  //Invalid File
  const invalidFile = new File(["dummy content"], "example.pdf", {
    type: "application/pdf",
  });

  render(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        type="image"
        onError={error}
      />
    </Provider>,
  );

  const input = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(input, "files", {
    value: [invalidFile],
    configurable: true,
  });
  fireEvent.change(input);

  //Valid File
  const validFile = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  Object.defineProperty(input, "files", {
    value: [validFile],
  });
  fireEvent.change(input);

  expect(error).toHaveBeenCalledTimes(1);
});

test("Single - File Extension Test", async () => {
  const error = jest.fn();
  window.URL.createObjectURL = function() {};

  //Invalid File
  const invalidFile = new File(["dummy content"], "example.exe", {
    type: "application/octet-stream",
  });

  render(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        type="file"
        onError={error}
      />
    </Provider>,
  );
  const input = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(input, "files", {
    value: [invalidFile],
    configurable: true,
  });
  fireEvent.change(input);

  //Valid File
  const validFile = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  Object.defineProperty(input, "files", {
    value: [validFile],
  });
  fireEvent.change(input);

  expect(error).toHaveBeenCalledTimes(1);
});

test("Single - Custom Extension Test", async () => {
  const error = jest.fn();
  window.URL.createObjectURL = function() {};

  //Invalid File
  const invalidFile = new File(["dummy content"], "example.exe", {
    type: "application/octet-stream",
  });

  const { rerender } = render(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        type=".png, .pdf"
        onError={error}
      />
    </Provider>,
  );
  const input = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(input, "files", {
    value: [invalidFile],
    configurable: true,
  });
  fireEvent.change(input);

  //Valid File
  const validFile = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  Object.defineProperty(input, "files", {
    value: [validFile],
  });
  fireEvent.change(input);

  //Mixed
  const mixed = new File(["dummy content"], "example.png", {
    type: "image/png",
  });
  rerender(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        type=".png, .asdw"
        onError={error}
      />
    </Provider>,
  );

  Object.defineProperty(input, "files", {
    value: [mixed],
  });
  fireEvent.change(input);

  expect(error).toHaveBeenCalledTimes(1);
});
//#endregion

//#region Multiple File Upload Tests
test("Multiple - Image Extension Test", async () => {
  const error = jest.fn();
  window.URL.createObjectURL = function() {};

  const imgFile = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  const invalidFile = new File(["dummy content"], "example.exe", {
    type: "application/octet-stream",
  });

  render(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        type="image"
        multiple={true}
        onError={error}
      />
    </Provider>,
  );

  const multipleInput = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(multipleInput, "files", {
    value: [imgFile, invalidFile],
  });
  fireEvent.change(multipleInput);

  expect(error).toHaveBeenCalledTimes(1);
});

test("Multiple - File Extension Test", async () => {
  const error = jest.fn();
  window.URL.createObjectURL = function() {};

  const imgFile = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  const file = new File(["dummy content"], "example.jpg", {
    type: "image/jpeg",
  });

  const invalidFile = new File(["dummy content"], "example.exe", {
    type: "application/octet-stream",
  });

  render(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        type="file"
        multiple={true}
        onError={error}
      />
    </Provider>,
  );

  const multipleInput = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(multipleInput, "files", {
    value: [imgFile, file, invalidFile],
  });
  fireEvent.change(multipleInput);

  expect(error).toHaveBeenCalledTimes(1);
});

test("Multiple - Custom Extension Test", async () => {
  const error = jest.fn();
  window.URL.createObjectURL = function() {};

  const imgFile = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  const file = new File(["dummy content"], "example.jpg", {
    type: "image/jpeg",
  });

  const invalidFile = new File(["dummy content"], "example.exe", {
    type: "application/octet-stream",
  });

  render(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        type=".png, .jpeg, .pdf"
        multiple={true}
        onError={error}
      />
    </Provider>,
  );

  const multipleInput = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(multipleInput, "files", {
    value: [imgFile, file, invalidFile],
  });
  fireEvent.change(multipleInput);

  expect(error).toHaveBeenCalledTimes(1);
});
//#endregion

test("On Upload test", async () => {
  const onUpload = jest.fn();
  const file = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  const { rerender } = render(
    <Provider>
      <FileComponent themed prefixClassName="test" onUpload={onUpload} />
    </Provider>,
  );

  const input = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(input, "files", {
    value: [file],
  });

  fireEvent.change(input);
  expect(onUpload).toHaveBeenCalled();
});

test("Custom Validate test", async () => {
  const customValidate = jest.fn();
  const file = new File(["dummy content"], "example.png", {
    type: "image/png",
  });

  render(
    <Provider>
      <FileComponent
        themed
        prefixClassName="test"
        customValidate={customValidate}
      />
    </Provider>,
  );

  const input = document.getElementsByClassName("test-input")[0];

  Object.defineProperty(input, "files", {
    value: [file],
  });

  fireEvent.change(input);
  expect(customValidate).toHaveBeenCalled();
});
