// 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 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';

import 'semantics_tester.dart';

void main() {
  testWidgets('Semantics can merge sibling group', (WidgetTester tester) async {
    final SemanticsTester semantics = SemanticsTester(tester);
    const SemanticsTag first = SemanticsTag('1');
    const SemanticsTag second = SemanticsTag('2');
    const SemanticsTag third = SemanticsTag('3');
    ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
      expect(configs.length, 3);
      final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
      final List<SemanticsConfiguration> sibling = <SemanticsConfiguration>[];
      // Merge first and third
      for (final SemanticsConfiguration config in configs) {
        if (config.tagsChildrenWith(first) || config.tagsChildrenWith(third)) {
          sibling.add(config);
        } else {
          builder.markAsMergeUp(config);
        }
      }
      builder.markAsSiblingMergeGroup(sibling);
      return builder.build();
    }
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Semantics(
          label: 'parent',
          child: TestConfigDelegate(
            delegate: delegate,
            child: Column(
              children: <Widget>[
                Semantics(
                  label: '1',
                  tagForChildren: first,
                  child: const SizedBox(width: 100, height: 100),
                  // this tests that empty nodes disappear
                ),
                Semantics(
                  label: '2',
                  tagForChildren: second,
                  child: const SizedBox(width: 100, height: 100),
                ),
                Semantics(
                  label: '3',
                  tagForChildren: third,
                  child: const SizedBox(width: 100, height: 100),
                ),
              ],
            ),
          ),
        ),
      ),
    );

    expect(semantics, hasSemantics(TestSemantics.root(
      children: <TestSemantics>[
        TestSemantics.rootChild(
          label: 'parent\n2',
        ),
        TestSemantics.rootChild(
          label: '1\n3',
        ),
      ],
    ), ignoreId: true, ignoreRect: true, ignoreTransform: true));
    semantics.dispose();
  });

  testWidgets('Semantics can drop semantics config', (WidgetTester tester) async {
    final SemanticsTester semantics = SemanticsTester(tester);
    const SemanticsTag first = SemanticsTag('1');
    const SemanticsTag second = SemanticsTag('2');
    const SemanticsTag third = SemanticsTag('3');
    ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
      final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
      // Merge first and third
      for (final SemanticsConfiguration config in configs) {
        if (config.tagsChildrenWith(first) || config.tagsChildrenWith(third)) {
          continue;
        }
        builder.markAsMergeUp(config);
      }
      return builder.build();
    }
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Semantics(
          label: 'parent',
          child: TestConfigDelegate(
            delegate: delegate,
            child: Column(
              children: <Widget>[
                Semantics(
                  label: '1',
                  tagForChildren: first,
                  child: const SizedBox(width: 100, height: 100),
                  // this tests that empty nodes disappear
                ),
                Semantics(
                  label: '2',
                  tagForChildren: second,
                  child: const SizedBox(width: 100, height: 100),
                ),
                Semantics(
                  label: '3',
                  tagForChildren: third,
                  child: const SizedBox(width: 100, height: 100),
                ),
              ],
            ),
          ),
        ),
      ),
    );

    expect(semantics, hasSemantics(TestSemantics.root(
      children: <TestSemantics>[
        TestSemantics.rootChild(
          label: 'parent\n2',
        ),
      ],
    ), ignoreId: true, ignoreRect: true, ignoreTransform: true));
    semantics.dispose();
  });

  testWidgets('Semantics throws when mark the same config twice case 1', (WidgetTester tester) async {
    const SemanticsTag first = SemanticsTag('1');
    const SemanticsTag second = SemanticsTag('2');
    const SemanticsTag third = SemanticsTag('3');
    ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
      final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
      // Marks the same one twice.
      builder.markAsMergeUp(configs.first);
      builder.markAsMergeUp(configs.first);
      return builder.build();
    }
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Semantics(
          label: 'parent',
          child: TestConfigDelegate(
            delegate: delegate,
            child: Column(
              children: <Widget>[
                Semantics(
                  label: '1',
                  tagForChildren: first,
                  child: const SizedBox(width: 100, height: 100),
                  // this tests that empty nodes disappear
                ),
                Semantics(
                  label: '2',
                  tagForChildren: second,
                  child: const SizedBox(width: 100, height: 100),
                ),
                Semantics(
                  label: '3',
                  tagForChildren: third,
                  child: const SizedBox(width: 100, height: 100),
                ),
              ],
            ),
          ),
        ),
      ),
    );

    expect(tester.takeException(), isAssertionError);
  });

  testWidgets('Semantics throws when mark the same config twice case 2', (WidgetTester tester) async {
    const SemanticsTag first = SemanticsTag('1');
    const SemanticsTag second = SemanticsTag('2');
    const SemanticsTag third = SemanticsTag('3');
    ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
      final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
      // Marks the same one twice.
      builder.markAsMergeUp(configs.first);
      builder.markAsSiblingMergeGroup(<SemanticsConfiguration>[configs.first]);
      return builder.build();
    }
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: Semantics(
          label: 'parent',
          child: TestConfigDelegate(
            delegate: delegate,
            child: Column(
              children: <Widget>[
                Semantics(
                  label: '1',
                  tagForChildren: first,
                  child: const SizedBox(width: 100, height: 100),
                  // this tests that empty nodes disappear
                ),
                Semantics(
                  label: '2',
                  tagForChildren: second,
                  child: const SizedBox(width: 100, height: 100),
                ),
                Semantics(
                  label: '3',
                  tagForChildren: third,
                  child: const SizedBox(width: 100, height: 100),
                ),
              ],
            ),
          ),
        ),
      ),
    );

    expect(tester.takeException(), isAssertionError);
  });

  testWidgets('RenderObject with semantics child delegate will mark correct boundary dirty', (WidgetTester tester) async {
    final UniqueKey inner = UniqueKey();
    final UniqueKey boundaryParent = UniqueKey();
    final UniqueKey grandBoundaryParent = UniqueKey();
    ChildSemanticsConfigurationsResult delegate(List<SemanticsConfiguration> configs) {
      final ChildSemanticsConfigurationsResultBuilder builder = ChildSemanticsConfigurationsResultBuilder();
      configs.forEach(builder.markAsMergeUp);
      return builder.build();
    }
    await tester.pumpWidget(
      Directionality(
        textDirection: TextDirection.ltr,
        child: MarkSemanticsDirtySpy(
          key: grandBoundaryParent,
          child: MarkSemanticsDirtySpy(
            key: boundaryParent,
            child: TestConfigDelegate(
              delegate: delegate,
              child: Column(
                children: <Widget>[
                  Semantics(
                    label: 'label',
                    child: MarkSemanticsDirtySpy(
                      key: inner,
                      child: const Text('inner'),
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );

    final RenderMarkSemanticsDirtySpy innerObject = tester.renderObject<RenderMarkSemanticsDirtySpy>(find.byKey(inner));
    final RenderTestConfigDelegate objectWithDelegate = tester.renderObject<RenderTestConfigDelegate>(find.byType(TestConfigDelegate));
    final RenderMarkSemanticsDirtySpy boundaryParentObject = tester.renderObject<RenderMarkSemanticsDirtySpy>(find.byKey(boundaryParent));
    final RenderMarkSemanticsDirtySpy grandBoundaryParentObject = tester.renderObject<RenderMarkSemanticsDirtySpy>(find.byKey(grandBoundaryParent));
    void resetBuildState() {
      innerObject.hasRebuildSemantics = false;
      boundaryParentObject.hasRebuildSemantics = false;
      grandBoundaryParentObject.hasRebuildSemantics = false;
    }
    // Sanity check
    expect(innerObject.hasRebuildSemantics, isTrue);
    expect(boundaryParentObject.hasRebuildSemantics, isTrue);
    expect(grandBoundaryParentObject.hasRebuildSemantics, isTrue);
    resetBuildState();

    innerObject.markNeedsSemanticsUpdate();
    await tester.pump();
    // Inner boundary should not trigger rebuild above it.
    expect(innerObject.hasRebuildSemantics, isTrue);
    expect(boundaryParentObject.hasRebuildSemantics, isFalse);
    expect(grandBoundaryParentObject.hasRebuildSemantics, isFalse);
    resetBuildState();

    objectWithDelegate.markNeedsSemanticsUpdate();
    await tester.pump();
    // object with delegate rebuilds up to grand parent boundary;
    expect(innerObject.hasRebuildSemantics, isTrue);
    expect(boundaryParentObject.hasRebuildSemantics, isTrue);
    expect(grandBoundaryParentObject.hasRebuildSemantics, isTrue);
    resetBuildState();

    boundaryParentObject.markNeedsSemanticsUpdate();
    await tester.pump();
    // Render objects in between child delegate and grand boundary parent does
    // not mark the grand boundary parent dirty because it should not change the
    // generated sibling nodes.
    expect(innerObject.hasRebuildSemantics, isTrue);
    expect(boundaryParentObject.hasRebuildSemantics, isTrue);
    expect(grandBoundaryParentObject.hasRebuildSemantics, isFalse);
  });
}

class MarkSemanticsDirtySpy extends SingleChildRenderObjectWidget {
  const MarkSemanticsDirtySpy({super.key, super.child});
  @override
  RenderMarkSemanticsDirtySpy createRenderObject(BuildContext context) => RenderMarkSemanticsDirtySpy();
}

class RenderMarkSemanticsDirtySpy extends RenderProxyBox {
  RenderMarkSemanticsDirtySpy();
  bool hasRebuildSemantics = false;

  @override
  void describeSemanticsConfiguration(SemanticsConfiguration config) {
    config.isSemanticBoundary = true;
  }

  @override
  void assembleSemanticsNode(
    SemanticsNode node,
    SemanticsConfiguration config,
    Iterable<SemanticsNode> children,
  ) {
    hasRebuildSemantics = true;
  }
}

class TestConfigDelegate extends SingleChildRenderObjectWidget {
  const TestConfigDelegate({super.key, required this.delegate, super.child});
  final ChildSemanticsConfigurationsDelegate delegate;

  @override
  RenderTestConfigDelegate createRenderObject(BuildContext context) => RenderTestConfigDelegate(
    delegate: delegate,
  );

  @override
  void updateRenderObject(BuildContext context, RenderTestConfigDelegate renderObject) {
    renderObject.delegate = delegate;
  }
}

class RenderTestConfigDelegate extends RenderProxyBox {
  RenderTestConfigDelegate({
    ChildSemanticsConfigurationsDelegate? delegate,
  }) : _delegate = delegate;

  ChildSemanticsConfigurationsDelegate? get delegate => _delegate;
  ChildSemanticsConfigurationsDelegate? _delegate;
  set delegate(ChildSemanticsConfigurationsDelegate? value) {
    if (value != _delegate) {
      markNeedsSemanticsUpdate();
    }
    _delegate = value;
  }

  @override
  void describeSemanticsConfiguration(SemanticsConfiguration config) {
    config.childConfigurationsDelegate = delegate;
  }
}
