import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'
    show ReplyInfo, DetailListReply, Mode;
import 'package:PiliPlus/grpc/reply.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/common/reply_controller.dart';
import 'package:PiliPlus/pages/video/reply_new/view.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/request_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:get/get_navigation/src/dialog/dialog_route.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';

class VideoReplyReplyController extends ReplyController
    with GetSingleTickerProviderStateMixin {
  VideoReplyReplyController({
    required this.hasRoot,
    required this.id,
    required this.oid,
    required this.rpid,
    required this.dialog,
    required this.replyType,
    required this.isDialogue,
  });
  final int? dialog;
  final bool isDialogue;
  final itemScrollCtr = ItemScrollController();
  bool hasRoot = false;
  int? id;
  // 视频aid 请求时使用的oid
  int oid;
  // rpid 请求楼中楼回复
  int rpid;
  int replyType; // = ReplyType.video;

  ReplyInfo? firstFloor;

  int? index;
  AnimationController? controller;

  late final horizontalPreview = Pref.horizontalPreview;

  @override
  dynamic get sourceId => replyType == 1 ? IdUtils.av2bv(oid) : oid;

  @override
  void onInit() {
    super.onInit();
    mode.value = Mode.MAIN_LIST_TIME;
    queryData();
  }

  @override
  Future<void> onRefresh() {
    paginationReply = null;
    return super.onRefresh();
  }

  @override
  List<ReplyInfo>? getDataList(response) {
    return isDialogue ? response.replies : response.root.replies;
  }

  @override
  bool customHandleResponse(bool isRefresh, Success response) {
    final data = response.response;

    upMid ??= data.subjectControl.upMid;
    paginationReply = data.paginationReply;
    isEnd = data.cursor.isEnd;

    // reply2Reply // isDialogue.not
    if (data is DetailListReply) {
      count.value = data.root.count.toInt();
      if (isRefresh && firstFloor == null) {
        firstFloor = data.root;
      }
      if (id != null) {
        index = data.root.replies.indexWhere((item) => item.id.toInt() == id);
        if (index == -1) {
          index = null;
        } else {
          controller = AnimationController(
            duration: const Duration(milliseconds: 300),
            vsync: this,
          );
          WidgetsBinding.instance.addPostFrameCallback((_) async {
            if (index != null) {
              try {
                itemScrollCtr.jumpTo(
                  index: hasRoot ? index! + 3 : index! + 1,
                  alignment: 0.25,
                );
                await Future.delayed(const Duration(milliseconds: 800));
                await controller?.forward();
                index = null;
              } catch (_) {}
            }
          });
        }
        id = null;
      }
    }

    return false;
  }

  @override
  Future<LoadingState> customGetData() => isDialogue
      ? ReplyGrpc.dialogList(
          type: replyType,
          oid: oid,
          root: rpid,
          dialog: dialog!,
          offset: paginationReply?.nextOffset,
        )
      : ReplyGrpc.detailList(
          type: replyType,
          oid: oid,
          root: rpid,
          rpid: id ?? 0,
          mode: mode.value,
          offset: paginationReply?.nextOffset,
        );

  @override
  void queryBySort() {
    mode.value = mode.value == Mode.MAIN_LIST_HOT
        ? Mode.MAIN_LIST_TIME
        : Mode.MAIN_LIST_HOT;
    onReload();
  }

  @override
  void onReply(
    BuildContext context, {
    int? oid,
    ReplyInfo? replyItem,
    int? replyType,
    int? index,
  }) {
    assert(replyItem != null && index != null);
    final oid = replyItem!.oid.toInt();
    final root = replyItem.id.toInt();
    final key = oid + root;

    Navigator.of(context)
        .push(
      GetDialogRoute(
        pageBuilder: (buildContext, animation, secondaryAnimation) {
          return ReplyPage(
            oid: oid,
            root: root,
            parent: root,
            replyType: this.replyType,
            replyItem: replyItem,
            items: savedReplies[key],
            onSave: (reply) {
              if (reply.isEmpty) {
                savedReplies.remove(key);
              } else {
                savedReplies[key] = reply.toList();
              }
            },
          );
        },
        transitionDuration: const Duration(milliseconds: 500),
        transitionBuilder: (context, animation, secondaryAnimation, child) {
          const begin = Offset(0.0, 1.0);
          const end = Offset.zero;
          const curve = Curves.linear;

          var tween =
              Tween(begin: begin, end: end).chain(CurveTween(curve: curve));

          return SlideTransition(
            position: animation.drive(tween),
            child: child,
          );
        },
      ),
    )
        .then((res) {
      if (res != null) {
        savedReplies.remove(key);
        ReplyInfo replyInfo = RequestUtils.replyCast(res);

        count.value += 1;
        loadingState
          ..value.dataOrNull?.insert(index! + 1, replyInfo)
          ..refresh();
        if (enableCommAntifraud) {
          onCheckReply(replyInfo, isManual: false);
        }
      }
    });
  }

  @override
  void onClose() {
    controller?.dispose();
    super.dispose();
  }
}
