// 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.

// @dart = 2.6
import 'dart:async';

import 'package:args/command_runner.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;
import 'package:watcher/watcher.dart';

import 'environment.dart';
import 'utils.dart';

class BuildCommand extends Command<bool> with ArgUtils {
  BuildCommand() {
    argParser
      ..addFlag(
        'watch',
        abbr: 'w',
        help: 'Run the build in watch mode so it rebuilds whenever a change'
            'is made.',
      );
  }

  @override
  String get name => 'build';

  @override
  String get description => 'Build the Flutter web engine.';

  bool get isWatchMode => boolArg('watch');

  @override
  FutureOr<bool> run() async {
    final FilePath libPath = FilePath.fromWebUi('lib');
    final Pipeline buildPipeline = Pipeline(steps: <PipelineStep>[
      gn,
      () => ninja(),
    ]);
    await buildPipeline.start();

    if (isWatchMode) {
      print('Initial build done!');
      print('Watching directory: ${libPath.relativeToCwd}/');
      PipelineWatcher(
        dir: libPath.absolute,
        pipeline: buildPipeline,
        // Ignore font files that are copied whenever tests run.
        ignore: (event) => event.path.endsWith('.ttf'),
      ).start();
      // Return a never-ending future.
      return Completer<bool>().future;
    } else {
      return true;
    }
  }
}

Future<void> gn() {
  print('Running gn...');
  return runProcess(
    path.join(environment.flutterDirectory.path, 'tools', 'gn'),
    <String>[
      '--unopt',
      '--full-dart-sdk',
    ],
  );
}

// TODO(mdebbar): Make the ninja step interruptable in the pipeline.
Future<void> ninja() {
  print('Running autoninja...');
  return runProcess('autoninja', <String>[
    '-C',
    environment.hostDebugUnoptDir.path,
  ]);
}

enum PipelineStatus {
  idle,
  started,
  stopping,
  stopped,
  error,
  done,
}

typedef PipelineStep = Future<void> Function();

class Pipeline {
  Pipeline({@required this.steps});

  final Iterable<PipelineStep> steps;

  Future<dynamic> _currentStepFuture;

  PipelineStatus status = PipelineStatus.idle;

  Future<void> start() async {
    status = PipelineStatus.started;
    try {
      for (PipelineStep step in steps) {
        if (status != PipelineStatus.started) {
          break;
        }
        _currentStepFuture = step();
        await _currentStepFuture;
      }
      status = PipelineStatus.done;
    } catch (error, stackTrace) {
      status = PipelineStatus.error;
      print('Error in the pipeline: $error');
      print(stackTrace);
    } finally {
      _currentStepFuture = null;
    }
  }

  Future<void> stop() {
    status = PipelineStatus.stopping;
    return (_currentStepFuture ?? Future<void>.value(null)).then((_) {
      status = PipelineStatus.stopped;
    });
  }
}

typedef WatchEventPredicate = bool Function(WatchEvent event);

class PipelineWatcher {
  PipelineWatcher({
    @required this.dir,
    @required this.pipeline,
    this.ignore,
  }) : watcher = DirectoryWatcher(dir);

  /// The path of the directory to watch for changes.
  final String dir;

  /// The pipeline to be executed when an event is fired by the watcher.
  final Pipeline pipeline;

  /// Used to watch a directory for any file system changes.
  final DirectoryWatcher watcher;

  /// A callback that determines whether to rerun the pipeline or not for a
  /// given [WatchEvent] instance.
  final WatchEventPredicate ignore;

  void start() {
    watcher.events.listen(_onEvent);
  }

  int _pipelineRunCount = 0;
  Timer _scheduledPipeline;

  void _onEvent(WatchEvent event) {
    if (ignore != null && ignore(event)) {
      return;
    }

    final String relativePath = path.relative(event.path, from: dir);
    print('- [${event.type}] ${relativePath}');

    _pipelineRunCount++;
    _scheduledPipeline?.cancel();
    _scheduledPipeline = Timer(const Duration(milliseconds: 100), () {
      _scheduledPipeline = null;
      _runPipeline();
    });
  }

  void _runPipeline() {
    int runCount;
    switch (pipeline.status) {
      case PipelineStatus.started:
        pipeline.stop().then((_) {
          runCount = _pipelineRunCount;
          pipeline.start().then((_) => _pipelineDone(runCount));
        });
        break;

      case PipelineStatus.stopping:
        // We are already trying to stop the pipeline. No need to do anything.
        break;

      default:
        runCount = _pipelineRunCount;
        pipeline.start().then((_) => _pipelineDone(runCount));
        break;
    }
  }

  void _pipelineDone(int pipelineRunCount) {
    if (pipelineRunCount == _pipelineRunCount) {
      print('*** Done! ***');
    }
  }
}
