/*
 * Copyright 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License")
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import "@testing-library/jest-dom";
import "babel-polyfill";
import { EventEmitter } from "events";
import React from "react";
import { render, fireEvent, screen, waitFor } from "@testing-library/react";
import Emulator from "../src/components/emulator/emulator";
import * as Proto from "../src/proto/emulator_controller_pb";
import * as Rtc from "../src/proto/rtc_service_pb";
import {
  RtcService,
  EmulatorControllerService,
} from "../src/proto/emulator_web_client";

jest.mock("../src/proto/emulator_web_client");

// See https://github.com/testing-library/react-testing-library/issues/470
// As well as https://github.com/facebook/react/issues/10389
// All because of the "muted" tag on our video element inside webrtc_view
const renderIgnoringUnstableFlushDiscreteUpdates = (component) => {
  // tslint:disable: no-console
  const originalError = console.error;
  const error = jest.fn();
  console.error = error;
  const result = render(component);
  expect(error).toHaveBeenCalledTimes(1);
  expect(error).toHaveBeenCalledWith(
    "Warning: unstable_flushDiscreteUpdates: Cannot flush updates when React is already rendering.%s",
    expect.any(String)
  );
  console.error = originalError;
  // tslint:enable: no-console
  return result;
};

describe("The emulator", () => {
  let fakeScreen;

  beforeEach(() => {
    // Clear all instances and calls to constructor and all methods:
    RtcService.mockClear();
    EmulatorControllerService.mockClear();
  });

  test("Creates gRPC services", async () => {
    let state;
    renderIgnoringUnstableFlushDiscreteUpdates(
      <Emulator uri="/test" width={300} height={300} />
    );

    expect(EmulatorControllerService).toHaveBeenCalled();
    expect(RtcService).toHaveBeenCalled();
    // Shipped out a gps call
  });
  test("Tries to establish a webrtc connection", async () => {
    let state;

    renderIgnoringUnstableFlushDiscreteUpdates(
      <Emulator
        uri="/test"
        width={300}
        height={300}
        onStateChange={(e) => {
          state = e;
        }}
      />
    );

    await waitFor(() => state === "connecting");
    expect(RtcService).toHaveBeenCalled();
  });

  test("Sends a gps location to the emulator", async () => {
    // Let's go to Seattle!
    renderIgnoringUnstableFlushDiscreteUpdates(
      <Emulator
        uri="/test"
        width={300}
        height={300}
        gps={{ latitude: 47.6062, longitude: 122.3321 }}
      />
    );

    const setGps = EmulatorControllerService.mock.instances[0].setGps;
    expect(setGps).toHaveBeenCalled();

    const location = new Proto.GpsState();
    location.setLatitude(47.6062);
    location.setLongitude(122.3321);
    location.setAltitude(undefined);
    location.setBearing(undefined);
    location.setSpeed(undefined);
    expect(setGps).toHaveBeenCalledWith(location);
  });

  test("The png view requests images", async () => {
    let pngCall = false
    EmulatorControllerService.mockImplementation(() => {
      return {
        streamScreenshot: jest.fn((request) => {
            pngCall = true
          return { on: jest.fn(), cancel: jest.fn() };
        }),
        getStatus: jest.fn(() => {}),
      };
    });

    render(<Emulator uri="/test" width={300} height={300} view="png" />);
    expect(pngCall).toBeTruthy()
  });
});