// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';

import 'package:image/image.dart';
import 'package:webdriver/async_io.dart' show WebDriver, createDriver;

import 'browser.dart';

abstract class WebDriverBrowserEnvironment extends BrowserEnvironment {
  late int portNumber;
  late final Process _driverProcess;

  Future<Process> spawnDriverProcess();
  Uri get driverUri;

  /// Finds and returns an unused port on the test host in the local port range.
  Future<int> pickUnusedPort() async {
    // Use bind to allocate an unused port, then unbind from that port to
    // make it available for use.
    final ServerSocket socket = await ServerSocket.bind('localhost', 0);
    final int port = socket.port;
    await socket.close();

    return port;
  }


  @override
  Future<void> prepare() async {
    portNumber = await pickUnusedPort();

    _driverProcess = await spawnDriverProcess();

    _driverProcess.stderr
        .transform(utf8.decoder)
        .transform(const LineSplitter())
        .listen((String error) {
      print('[Webdriver][Error] $error');
    });

    _driverProcess.stdout
        .transform(utf8.decoder)
        .transform(const LineSplitter())
        .listen((String log) {
      print('[Webdriver] $log');
    });
  }

  @override
  Future<void> cleanup() async {
    _driverProcess.kill();
  }

  @override
  Future<Browser> launchBrowserInstance(Uri url, {bool debug = false}) async {
    while (true) {
      try {
        final WebDriver driver = await createDriver(
          uri: driverUri, desired: <String, dynamic>{'browserName': packageTestRuntime.identifier});
        return WebDriverBrowser(driver, url);
      } on SocketException {
        // Sometimes we may try to connect before the web driver port is ready.
        // So we should retry here. Note that if there was some issue with the
        // webdriver process, we may loop infinitely here, so we're relying on
        // the test timeout to kill us if it takes too long to connect.
        print('Failed to connect to webdriver process. Retrying in 100 ms');
        await Future<void>.delayed(const Duration(milliseconds: 100));
      } catch (exception) {
        rethrow;
      }
    }
  }
}

class WebDriverBrowser extends Browser {
  WebDriverBrowser(this._driver, this._url) {
    _driver.get(_url);
  }

  final WebDriver _driver;
  final Uri _url;
  final Completer<void> _onExitCompleter = Completer<void>();

  @override
  Future<void> close() async {
    await (await _driver.window).close();
    if (!_onExitCompleter.isCompleted) {
      _onExitCompleter.complete();
    }
  }

  @override
  Future<void> get onExit => _onExitCompleter.future;

  @override
  bool get supportsScreenshots => true;

  @override
  Future<Image> captureScreenshot(Rectangle<num> region) async {
    final Image image = decodePng(await _driver.captureScreenshotAsList())!;
    return copyCrop(image, region.left.round(), region.top.round(),
        region.width.round(), region.height.round());
  }
}
