import 'dart:async';

import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:mnemo_cards/features/packs/images_holder.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';
import 'package:collection/collection.dart';
import 'package:reorderables/reorderables.dart';
import 'package:rxdart/rxdart.dart';

import '../../di/locator.dart';
import '../../utils/string_helper.dart';
import '../../domain/router/app_router.gr.dart';
import '../../main.dart';
import '../feedback_builder.dart';
import '../game_card_widget.dart';
import 'cards_view_controller.dart';

class CardsView extends StatefulWidget {
  final CardPackDto cardPack;
  final CardsViewController controller;
  final List<int> cardsOrder = [];

  CardsView(this.controller, this.cardPack);

  @override
  State<StatefulWidget> createState() => _CardsViewState();
}

class _CardsViewState extends State<CardsView>
    with SingleTickerProviderStateMixin {
  CardPackDto get cardPack => widget.cardPack;

  CardsViewController get controller => widget.controller;
  var _subscription = CompositeSubscription();

  late AnimationController _animationController;

  bool expanded = false;
  bool favorite = false;

  final wrapKey = GlobalKey();

  void _onStateChanged(CardsViewState state) async {
    favorite = state.favorite;
    if (state.expanded != expanded) {
      expanded = state.expanded;
      if (expanded) {
        await controller.animateTo(0);
        _animationController.animateTo(
          1.0,
          duration:
              Duration(milliseconds: (100 * state.packCards.length / 3).ceil()),
        );
      } else {
        _animationController.animateBack(
          0.0,
          duration:
              Duration(milliseconds: (100 * state.packCards.length / 3).ceil()),
        );
      }
    }
  }

  @override
  void didUpdateWidget(CardsView oldWidget) {
    super.didUpdateWidget(oldWidget);
    _subscription.cancel();
    _subscription = CompositeSubscription();
    controller.asStream.listen(_onStateChanged).addTo(_subscription);
  }

  @override
  void initState() {
    super.initState();
    expanded = controller.state.expanded;
    favorite = controller.state.favorite;
    _animationController = AnimationController(vsync: this);
    _subscription.cancel();
    _subscription = CompositeSubscription();
    controller.asStream.listen(_onStateChanged).addTo(_subscription);
  }

  @override
  void dispose() {
    _subscription.cancel();
    _animationController.dispose();
    super.dispose();
  }

  void onCardTap(List<GameCardDto> cards, GameCardDto card) async {
    final playing = appRouter.push(
      PageRouteInfo(
        CardGamePage.name,
        args: CardGamePageArgs(
          cards: cards,
          color: cardPack.color?.asColor,
          startCardId: card.id,
          infinite: true,
          shuffle: false,
          // id: cardPack.dto.id.toString(),
        ),
      ),
    );
    final id = await playing;
    // if (id is int) {
    //   final index = cardPack.cards.indexWhere((c) => c.id == id);
    //   if (index >= 0) {
    //     print('jump to $index');
    //     controller.jumpTo(index);
    //   }
    // }
  }

  @override
  Widget build(BuildContext context) {
    final cardWidth = MediaQuery.of(context).size.width / 3;
    final imageWidth = cardWidth * 0.93;

    return StreamBuilder(
        stream: controller.cardsStream,
        builder: (context, snapshot) {
          if (!snapshot.hasData) {
            return SizedBox();
          }
          final packCards = snapshot.requireData;

          if (packCards.isEmpty) {
            return _NoCards(
              favorite: favorite,
              height: cardWidth * 4 / 3,
            );
          }

          controller.imageWidth = imageWidth;
          final animation = _animationController.view;
          return AnimatedBuilder(
              animation: animation,
              builder: (context, child) {
                return Column(
                  children: [
                    SingleChildScrollView(
                      controller: controller.cardsScrollController,
                      scrollDirection:
                          animation.value > 0 ? Axis.vertical : Axis.horizontal,
                      physics: animation.value > 0
                          ? NeverScrollableScrollPhysics()
                          : null,
                      child: Container(
                        alignment: Alignment.topCenter,
                        height: cardWidth * 4 / 3 +
                            ((packCards.length / 3).ceil() * 4 / 3 * cardWidth -
                                    cardWidth * 4 / 3) *
                                animation.value,
                        child: Builder(builder: (context) {
                          return ReorderableWrap(
                            key: wrapKey,
                            onReorder: (int from, int to) {
                              controller.onOrderChanged(from, to);
                            },
                            buildDraggableFeedback: FeedbackBuilder.simple,
                            padding: EdgeInsets.symmetric(
                              horizontal: (cardWidth - imageWidth - 1),
                              vertical: (cardWidth - imageWidth - 1),
                            ),
                            runSpacing: (cardWidth - imageWidth - 1) * 2,
                            spacing: (cardWidth - imageWidth - 1) * 2,
                            children: List.generate(packCards.length, (index) {
                              final card = packCards[index];
                              final memoryImage = card.memoryImage;
                              if (memoryImage == null) {
                                return SizedBox();
                              }
                              return Container(
                                height: 2 * imageWidth - cardWidth * 2 / 3 + 2,
                                width: 2 * imageWidth - cardWidth + 2,
                                alignment: Alignment.topCenter,
                                child: Container(
                                  height: imageWidth * 4 / 3,
                                  child: _CardBuilder(
                                    cardPack,
                                    card,
                                    memoryImage,
                                    (card) => onCardTap(packCards, card),
                                  ),
                                ),
                              );
                            }),
                          );
                        }),
                      ),
                    ),
                  ],
                );
              });
        });
  }
}

class _CardBuilder extends StatelessWidget {
  final GameCardDto card;
  final CardPackDto cardPack;
  final MemoryImage image;
  final Function(GameCardDto) onTap;

  _CardBuilder(
    this.cardPack,
    this.card,
    this.image,
    this.onTap,
  );

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      key: ObjectKey(card),
      onTap: () => onTap(card),
      child: Hero(
        key: ValueKey('${card.id}'),
        tag: card.id,
        child: GameCardDecoration(
          alpha: 0.0,
          borderColor: cardPack.color?.asColor,
          child: FrontCard(
            card,
            image,
            alpha: 0,
          ),
        ),
        createRectTween: (a, b) => RectTween(begin: a, end: b),
        flightShuttleBuilder: (flightC, a, dir, fromC, toC) {
          return AnimatedBuilder(
            animation: a,
            builder: (context, child) => GameCardDecoration(
              alpha: a.value,
              borderColor: cardPack.color?.asColor,
              child: FrontCard(
                card,
                card.memoryImage!,
                alpha: a.value,
              ),
            ),
          );
        },
      ),
    );
  }
}

class _NoCards extends StatelessWidget {
  final bool favorite;
  final double height;

  _NoCards({
    required this.favorite,
    required this.height,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      height: height,
      alignment: Alignment.center,
      child: Text(
        favorite ? 'Нет любимых карточек' : 'Пока нет карточек',
        style: TextStyle(
          fontSize: 16.sp,
          fontWeight: FontWeight.w500,
        ),
        textAlign: TextAlign.center,
      ),
    );
  }
}
