// Copyright (C) 2019 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 {dingus} from 'dingusjs';

import {utf8Encode} from '../base/string_utils';
import {EnableTracingRequest, TraceConfig} from '../protos';

import {AdbStream, MockAdb, MockAdbStream} from './adb_interfaces';
import {AdbConsumerPort} from './adb_shell_controller';
import {Consumer} from './record_controller_interfaces';

function generateMockConsumer(): Consumer {
  return {
    onConsumerPortResponse: jest.fn(),
    onError: jest.fn(),
    onStatus: jest.fn(),
  };
}
const mainCallback = generateMockConsumer();
const adbMock = new MockAdb();
const adbController = new AdbConsumerPort(adbMock, mainCallback);
const mockIntArray = new Uint8Array();

const enableTracingRequest = new EnableTracingRequest();
enableTracingRequest.traceConfig = new TraceConfig();
const enableTracingRequestProto =
    EnableTracingRequest.encode(enableTracingRequest).finish();


test('handleCommand', async () => {
  adbController.findDevice = () => {
    return Promise.resolve(dingus<USBDevice>());
  };

  const enableTracing = jest.fn();
  adbController.enableTracing = enableTracing;
  await adbController.invoke('EnableTracing', mockIntArray);
  expect(enableTracing).toHaveBeenCalledTimes(1);

  const readBuffers = jest.fn();
  adbController.readBuffers = readBuffers;
  adbController.invoke('ReadBuffers', mockIntArray);
  expect(readBuffers).toHaveBeenCalledTimes(1);

  const sendErrorMessage = jest.fn();
  adbController.sendErrorMessage = sendErrorMessage;
  adbController.invoke('unknown', mockIntArray);
  expect(sendErrorMessage).toBeCalledWith('Method not recognized: unknown');
});

test('enableTracing', async () => {
  const mainCallback = generateMockConsumer();
  const adbMock = new MockAdb();
  const adbController = new AdbConsumerPort(adbMock, mainCallback);

  adbController.sendErrorMessage =
      jest.fn().mockImplementation((s) => console.error(s));

  const findDevice = jest.fn().mockImplementation(() => {
    return Promise.resolve({} as unknown as USBDevice);
  });
  adbController.findDevice = findDevice;

  const connectToDevice =
      jest.fn().mockImplementation((_: USBDevice) => Promise.resolve());
  adbMock.connect = connectToDevice;

  const stream: AdbStream = new MockAdbStream();
  const adbShell =
      jest.fn().mockImplementation((_: string) => Promise.resolve(stream));
  adbMock.shell = adbShell;


  const sendMessage = jest.fn();
  adbController.sendMessage = sendMessage;

  adbController.generateStartTracingCommand = (_) => 'CMD';

  await adbController.enableTracing(enableTracingRequestProto);
  expect(adbShell).toBeCalledWith('CMD');
  expect(sendMessage).toHaveBeenCalledTimes(0);


  stream.onData(utf8Encode('starting tracing Wrote 123 bytes'));
  stream.onClose();

  expect(adbController.sendErrorMessage).toHaveBeenCalledTimes(0);
  expect(sendMessage).toBeCalledWith({type: 'EnableTracingResponse'});
});


test('generateStartTracing', () => {
  adbController.traceDestFile = 'DEST';
  const testArray = new Uint8Array(1);
  testArray[0] = 65;
  const generatedCmd = adbController.generateStartTracingCommand(testArray);
  expect(generatedCmd)
      .toBe(`echo '${btoa('A')}' | base64 -d | perfetto -c - -o DEST`);
});

test('tracingEndedSuccessfully', () => {
  expect(
      adbController.tracingEndedSuccessfully(
          'Connected to the Perfetto traced service, starting tracing for 10000 ms\nWrote 564 bytes into /data/misc/perfetto-traces/trace'))
      .toBe(true);
  expect(
      adbController.tracingEndedSuccessfully(
          'Connected to the Perfetto traced service, starting tracing for 10000 ms'))
      .toBe(false);
  expect(
      adbController.tracingEndedSuccessfully(
          'Connected to the Perfetto traced service, starting tracing for 0 ms'))
      .toBe(false);
});
