jest.mock("../../services/uploadFile");

import {
  render,
  cleanup,
  screen,
  fireEvent,
  waitFor,
} from "@testing-library/react";

import { setUploadFileDelay } from "../../services/uploadFile";
import {
  FileUploadProvider,
  useFileUploadContext,
} from "../Contexts/FileUploadContext";
import { StatusProvider, useStatusContext } from "../Contexts/StatusContext";

const checkState = (uploading, progress, status, linkURL, message) => {
  expect(screen.getByTestId("uploading").innerHTML).toEqual(uploading);
  expect(screen.getByTestId("progress").innerHTML).toEqual(progress);
  expect(screen.getByTestId("status").innerHTML).toEqual(status);
  expect(screen.getByTestId("linkURL").innerHTML).toEqual(linkURL);
  expect(screen.getByTestId("message").innerHTML).toEqual(message);
};

describe("FileUploadContext", () => {
  beforeEach(() => {
    const TestComp = () => {
      const {
        progress,
        uploading,
        status,
        linkURL,
        upload,
        cancel,
      } = useFileUploadContext();
      const { message, setMessage } = useStatusContext();
      const TEST_FILE = [{ name: "test.jpg", size: 0 }];
      const TEST_ACCESSTOKEN = "ACCESSTOKEN";
      const TEST_FORMDATA = {
        packagename: "TEST",
        version: "VERSION",
        vehicles: ["VIN"],
      };
      const exec = async (form, token, file) => {
        try {
          await upload(form, token, file);
        } catch (e) {
          setMessage(e.message);
        }
      };

      return (
        <>
          <div data-testid="uploading">{uploading.toString()}</div>
          <div data-testid="progress">{progress.toString()}</div>
          <div data-testid="status">{status}</div>
          <div data-testid="message">{message}</div>
          <div data-testid="linkURL">{linkURL}</div>
          <button
            data-testid="uploadNoFile"
            onClick={() => {
              exec(TEST_FORMDATA, TEST_ACCESSTOKEN, null);
            }}
          />
          <button
            data-testid="uploadNoToken"
            onClick={() => {
              exec(TEST_FORMDATA, null, TEST_FILE);
            }}
          />
          <button
            data-testid="uploadNoFormData"
            onClick={() => {
              exec({}, TEST_ACCESSTOKEN, TEST_FILE);
            }}
          />
          <button
            data-testid="upload"
            onClick={() => exec(TEST_FORMDATA, TEST_ACCESSTOKEN, TEST_FILE)}
          />
          <button data-testid="cancel" onClick={() => cancel()} />
        </>
      );
    };
    render(
      <StatusProvider>
        <FileUploadProvider>
          <TestComp />
        </FileUploadProvider>
      </StatusProvider>
    );
  });

  afterEach(() => {
    cleanup();
  });

  it("Initial state", async () => {
    checkState("false", "0", "", "", "");
  });

  it("Upload no file", async () => {
    fireEvent.click(screen.getByTestId("uploadNoFile"));
    await waitFor(() =>
      expect(screen.getByTestId("message").innerHTML).not.toBe("")
    );
    checkState("false", "0", "", "", "File required");
  });

  it("Upload no access token", async () => {
    fireEvent.click(screen.getByTestId("uploadNoToken"));
    await waitFor(() =>
      expect(screen.getByTestId("message").innerHTML).not.toBe("")
    );
    checkState("false", "0", "", "", "Access token required");
  });

  it("Upload no form data", async () => {
    fireEvent.click(screen.getByTestId("uploadNoFormData"));
    await waitFor(() =>
      expect(screen.getByTestId("message").innerHTML).not.toBe("")
    );
    checkState("false", "0", "", "", "Package name required");
  });

  it("Upload file", async () => {
    fireEvent.click(screen.getByTestId("upload"));
    await waitFor(() =>
      expect(screen.getByTestId("progress").innerHTML).toEqual("100")
    );
    checkState("true", "100", "Uploaded test.jpg", "CLOUDFRONT_URL", "");
  });

  it("Cancel upload", async () => {
    setUploadFileDelay(true);
    fireEvent.click(screen.getByTestId("upload"));
    await waitFor(() =>
      expect(screen.getByTestId("progress").innerHTML).toEqual("50")
    );
    checkState("true", "50", "Uploading test.jpg", "", "");

    fireEvent.click(screen.getByTestId("cancel"));
    await waitFor(() =>
      expect(screen.getByTestId("progress").innerHTML).toEqual("0")
    );
    checkState("false", "0", "Upload cancelled", "", "");
  });
});
