// 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/io.dart' show WebDriver, createDriver;

import 'browser.dart';

abstract class WebDriverBrowserEnvironment extends BrowserEnvironment {
  late final 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());
  }
}
