// 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:async';

import 'package:flutter/material.dart';

import 'recorder.dart';

/// Creates a [Wrap] inside a ListView.
///
/// Tests large number of DOM nodes since image breaks up large canvas.
class BenchWrapBoxScroll extends WidgetRecorder {
  BenchWrapBoxScroll() : super(name: benchmarkName);

  static const String benchmarkName = 'bench_wrapbox_scroll';

  @override
  Widget createWidget() {
    return MaterialApp(
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      title: 'WrapBox Scroll Benchmark',
      home: const Scaffold(body: MyHomePage()),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late ScrollController scrollController;
  int block = 0;
  static const Duration stepDuration = Duration(milliseconds: 500);
  static const double stepDistance = 400;

  @override
  void initState() {
    super.initState();

    scrollController = ScrollController();

    // Without the timer the animation doesn't begin.
    Timer.run(() async {
      while (block < 25) {
        await scrollController.animateTo((block % 5) * stepDistance,
            duration: stepDuration, curve: Curves.easeInOut);
        block++;
      }
    });
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return ListView(
        controller: scrollController,
        children: <Widget>[
            Wrap(
              children: <Widget>[
                for (int i = 0; i < 30; i++)
                  FractionallySizedBox(
                    widthFactor: 0.2,
                    child: ProductPreview(i)), //need case1
                for (int i = 0; i < 30; i++) ProductPreview(i), //need case2
        ],
      ),
    ]);
  }
}

class ProductPreview extends StatelessWidget {
  const ProductPreview(this.previewIndex, {Key? key}) : super(key: key);

  final int previewIndex;

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      behavior: HitTestBehavior.translucent,
      onTap: () => print('tap'),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Container(
            margin: const EdgeInsets.all(23),
            padding: const EdgeInsets.all(18),
            decoration: const BoxDecoration(
              color: Color(0xfff9f9f9),
              shape: BoxShape.circle,
            ),
            child: Image.network(
              'assets/assets/Icon-192.png',
              width: 100,
              height: 100,
            ),
          ),
          const Text(
            'title',
          ),
          const SizedBox(
            height: 14,
          ),
          Wrap(
            alignment: WrapAlignment.center,
            children: <Widget>[
              ProductOption(
                optionText: '$previewIndex: option1',
              ),
              ProductOption(
                optionText: '$previewIndex: option2',
              ),
              ProductOption(
                optionText: '$previewIndex: option3',
              ),
              ProductOption(
                optionText: '$previewIndex: option4',
              ),
              ProductOption(
                optionText: '$previewIndex: option5',
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class ProductOption extends StatelessWidget {
  const ProductOption({
    Key? key,
    required this.optionText,
  }) : super(key: key);

  final String optionText;

  @override
  Widget build(BuildContext context) {
    return Container(
      constraints: const BoxConstraints(minWidth: 56),
      margin: const EdgeInsets.all(2),
      padding: const EdgeInsets.symmetric(horizontal: 11, vertical: 5),
      decoration: BoxDecoration(
        border: Border.all(
          width: 1,
          color: const Color(0xffebebeb),
        ),
        borderRadius: const BorderRadius.all(Radius.circular(15)),
      ),
      child: Text(
        optionText,
        maxLines: 1,
        textAlign: TextAlign.center,
        overflow: TextOverflow.ellipsis,
      ),
    );
  }
}
