// Copyright 2014 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:html' as html;
import 'dart:ui';

import 'package:collection/collection.dart';
import 'package:meta/dart2js.dart';

import 'package:flutter/foundation.dart';

/// Expected sequence of method calls.
const List<String> callChain = <String>['baz', 'bar', 'foo'];

final List<StackFrame> expectedProfileStackFrames = callChain.map<StackFrame>((String method) {
  return StackFrame(
    number: -1,
    packageScheme: '<unknown>',
    package: '<unknown>',
    packagePath: '<unknown>',
    line: -1,
    column: -1,
    className: 'Object',
    method: method,
    source: '',
  );
}).toList();

// TODO(yjbanov): fix these stack traces when https://github.com/flutter/flutter/issues/50753 is fixed.
const List<StackFrame> expectedDebugStackFrames = <StackFrame>[
  StackFrame(
    number: -1,
    packageScheme: 'package',
    package: 'packages',
    packagePath: 'web_integration/stack_trace.dart',
    line: 121,
    column: 3,
    className: '<unknown>',
    method: 'baz',
    source: '',
  ),
  StackFrame(
    number: -1,
    packageScheme: 'package',
    package: 'packages',
    packagePath: 'web_integration/stack_trace.dart',
    line: 116,
    column: 3,
    className: '<unknown>',
    method: 'bar',
    source: '',
  ),
  StackFrame(
    number: -1,
    packageScheme: 'package',
    package: 'packages',
    packagePath: 'web_integration/stack_trace.dart',
    line: 111,
    column: 3,
    className: '<unknown>',
    method: 'foo',
    source: '',
  ),
];

/// Tests that we do not crash while parsing Web stack traces.
///
/// This test is run in debug, profile, and release modes.
void main() {
  final StringBuffer output = StringBuffer();
  try {
    try {
      foo();
    } catch (expectedError, expectedStackTrace) {
      final List<StackFrame> parsedFrames = StackFrame.fromStackTrace(expectedStackTrace);
      if (parsedFrames.isEmpty) {
        throw Exception(
          'Failed to parse stack trace. Got empty list of stack frames.\n'
          'Stack trace:\n$expectedStackTrace'
        );
      }

      // Symbols in release mode are randomly obfuscated, so there's no good way to
      // validate the contents. However, profile mode can be checked.
      if (kProfileMode) {
        _checkStackFrameContents(parsedFrames, expectedProfileStackFrames, expectedStackTrace);
      }

      if (kDebugMode) {
        _checkStackFrameContents(parsedFrames, expectedDebugStackFrames, expectedStackTrace);
      }
    }
    output.writeln('--- TEST SUCCEEDED ---');
  } catch (unexpectedError, unexpectedStackTrace) {
    output.writeln('--- UNEXPECTED EXCEPTION ---');
    output.writeln(unexpectedError);
    output.writeln(unexpectedStackTrace);
    output.writeln('--- TEST FAILED ---');
  }
  print(output);
  html.HttpRequest.request(
    '/test-result',
    method: 'POST',
    sendData: '$output',
  );
}

@noInline
void foo() {
  bar();
}

@noInline
void bar() {
  baz();
}

@noInline
void baz() {
  throw Exception('Test error message');
}

void _checkStackFrameContents(List<StackFrame> parsedFrames, List<StackFrame> expectedFrames, dynamic stackTrace) {
  // Filter out stack frames outside this library so this test is less brittle.
  final List<StackFrame> actual = parsedFrames
    .where((StackFrame frame) => callChain.contains(frame.method))
    .toList();
  final bool stackFramesAsExpected = ListEquality<StackFrame>(StackFrameEquality()).equals(actual, expectedFrames);
  if (!stackFramesAsExpected) {
    throw Exception(
      'Stack frames parsed incorrectly:\n'
      'Expected:\n${expectedFrames.join('\n')}\n'
      'Actual:\n${actual.join('\n')}\n'
      'Stack trace:\n$stackTrace'
    );
  }
}

/// Use custom equality to ignore [StackFrame.source], which is not important
/// for the purposes of this test.
class StackFrameEquality implements Equality<StackFrame> {
  @override
  bool equals(StackFrame e1, StackFrame e2) {
    return e1.number == e2.number &&
           e1.packageScheme == e2.packageScheme &&
           e1.package == e2.package &&
           e1.packagePath == e2.packagePath &&
           e1.line == e2.line &&
           e1.column == e2.column &&
           e1.className == e2.className &&
           e1.method == e2.method;
  }

  @override
  int hash(StackFrame e) {
    return hashValues(e.number, e.packageScheme, e.package, e.packagePath, e.line, e.column, e.className, e.method);
  }

  @override
  bool isValidKey(Object o) => o is StackFrame;
}
