import 'dart:async';

import 'package:PiliPlus/common/widgets/self_sized_horizontal_list.dart';
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/id_utils.dart';
import 'package:expandable/expandable.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:get/get.dart';
import 'package:flutter/material.dart';
import 'package:PiliPlus/common/constants.dart';
import 'package:PiliPlus/pages/mine/controller.dart';
import 'package:PiliPlus/pages/video/detail/index.dart';
import 'package:PiliPlus/common/widgets/network_img_layer.dart';
import 'package:PiliPlus/common/widgets/stat/danmu.dart';
import 'package:PiliPlus/common/widgets/stat/view.dart';
import 'package:PiliPlus/models/video_detail_res.dart';
import 'package:PiliPlus/pages/video/detail/introduction/controller.dart';
import 'package:PiliPlus/utils/feed_back.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';

import 'widgets/action_item.dart';
import 'widgets/action_row_item.dart';
import 'widgets/page.dart';
import 'widgets/season.dart';

class VideoIntroPanel extends StatefulWidget {
  const VideoIntroPanel({
    super.key,
    required this.heroTag,
    required this.showAiBottomSheet,
    required this.showIntroDetail,
    required this.showEpisodes,
    required this.onShowMemberPage,
  });
  final String heroTag;
  final Function showAiBottomSheet;
  final Function showIntroDetail;
  final Function showEpisodes;
  final ValueChanged onShowMemberPage;

  @override
  State<VideoIntroPanel> createState() => _VideoIntroPanelState();
}

class _VideoIntroPanelState extends State<VideoIntroPanel>
    with AutomaticKeepAliveClientMixin, SingleTickerProviderStateMixin {
  late VideoIntroController videoIntroController;

  // 添加页面缓存
  @override
  bool get wantKeepAlive => true;

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

    videoIntroController = Get.put(VideoIntroController(), tag: widget.heroTag)
      ..heroTag = widget.heroTag;
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Obx(
      () => videoIntroController.videoDetail.value.title == null
          ? VideoInfo(
              loadingStatus: true,
              videoIntroController: videoIntroController,
              heroTag: widget.heroTag,
              showAiBottomSheet: widget.showAiBottomSheet,
              showIntroDetail: () => widget.showIntroDetail(
                videoIntroController.videoDetail.value,
                videoIntroController.videoTags,
              ),
              showEpisodes: widget.showEpisodes,
              onShowMemberPage: widget.onShowMemberPage,
            )
          : VideoInfo(
              key: ValueKey(widget.heroTag),
              loadingStatus: false,
              videoIntroController: videoIntroController,
              heroTag: widget.heroTag,
              showAiBottomSheet: widget.showAiBottomSheet,
              showIntroDetail: () => widget.showIntroDetail(
                videoIntroController.videoDetail.value,
                videoIntroController.videoTags,
              ),
              showEpisodes: widget.showEpisodes,
              onShowMemberPage: widget.onShowMemberPage,
            ),
    );
  }
}

class VideoInfo extends StatefulWidget {
  final bool loadingStatus;
  final String heroTag;
  final Function showAiBottomSheet;
  final Function showIntroDetail;
  final Function showEpisodes;
  final ValueChanged onShowMemberPage;
  final VideoIntroController videoIntroController;

  const VideoInfo({
    super.key,
    this.loadingStatus = false,
    required this.heroTag,
    required this.showAiBottomSheet,
    required this.showIntroDetail,
    required this.showEpisodes,
    required this.onShowMemberPage,
    required this.videoIntroController,
  });

  @override
  State<VideoInfo> createState() => _VideoInfoState();
}

class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
  late final VideoDetailController videoDetailCtr;

  Map get videoItem => videoIntroController.videoItem;
  VideoIntroController get videoIntroController => widget.videoIntroController;
  VideoDetailData get videoDetail =>
      widget.videoIntroController.videoDetail.value;

  late final _coinKey = GlobalKey<ActionItemState>();
  late final _favKey = GlobalKey<ActionItemState>();

  bool isProcessing = false;

  late final _horizontalMemberPage = GStorage.horizontalMemberPage;

  Widget _buildVideoTitle([bool isExpand = false]) => videoDetailCtr
          .enableSponsorBlock
      ? Obx(
          () => Text.rich(
            TextSpan(
              children: [
                if (videoDetailCtr.videoLabel.value.isNotEmpty) ...[
                  WidgetSpan(
                    alignment: PlaceholderAlignment.middle,
                    child: Container(
                      padding: const EdgeInsets.symmetric(
                        horizontal: 4,
                        vertical: 2,
                      ),
                      decoration: BoxDecoration(
                        color: Theme.of(context).colorScheme.secondaryContainer,
                        borderRadius: BorderRadius.circular(4),
                      ),
                      child: Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Stack(
                            alignment: Alignment.center,
                            children: [
                              Icon(
                                Icons.shield_outlined,
                                size: 16,
                                color: Theme.of(context)
                                    .colorScheme
                                    .onSecondaryContainer,
                              ),
                              Icon(
                                Icons.play_arrow_rounded,
                                size: 12,
                                color: Theme.of(context)
                                    .colorScheme
                                    .onSecondaryContainer,
                              ),
                            ],
                          ),
                          Text(
                            videoDetailCtr.videoLabel.value,
                            textScaler: TextScaler.linear(1),
                            strutStyle: StrutStyle(leading: 0, height: 1),
                            style: TextStyle(
                              height: 1,
                              fontSize: 13,
                              color: Theme.of(context)
                                  .colorScheme
                                  .onSecondaryContainer,
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                  TextSpan(text: ' '),
                ],
                TextSpan(
                    text: '${videoDetail.title ?? videoItem['title'] ?? ''}'),
              ],
            ),
            maxLines: isExpand ? null : 2,
            overflow: isExpand ? null : TextOverflow.ellipsis,
            style: const TextStyle(fontSize: 16),
          ),
        )
      : Text(
          '${videoDetail.title ?? videoItem['title'] ?? ''}',
          maxLines: isExpand ? null : 2,
          overflow: isExpand ? null : TextOverflow.ellipsis,
          style: const TextStyle(fontSize: 16),
        );

  void handleState(Future Function() action) async {
    if (isProcessing.not) {
      isProcessing = true;
      await action();
      isProcessing = false;
    }
  }

  @override
  void initState() {
    super.initState();
    videoDetailCtr = Get.find<VideoDetailController>(tag: widget.heroTag);

    if (videoIntroController.expandableCtr == null) {
      bool alwaysExapndIntroPanel = GStorage.alwaysExapndIntroPanel;

      videoIntroController.expandableCtr = ExpandableController(
        initialExpanded: alwaysExapndIntroPanel,
      );

      if (alwaysExapndIntroPanel.not && GStorage.exapndIntroPanelH) {
        WidgetsBinding.instance.addPostFrameCallback((_) {
          if (context.orientation == Orientation.landscape &&
              videoIntroController.expandableCtr?.expanded == false) {
            videoIntroController.expandableCtr?.toggle();
          }
        });
      }
    }
  }

  // 收藏
  showFavBottomSheet({type = 'tap'}) {
    if (videoIntroController.userInfo == null) {
      SmartDialog.showToast('账号未登录');
      return;
    }
    // 快速收藏 &
    // 点按 收藏至默认文件夹
    // 长按选择文件夹
    if (videoIntroController.enableQuickFav) {
      if (type == 'tap') {
        videoIntroController.actionFavVideo(type: 'default');
      } else {
        Utils.showFavBottomSheet(context: context, ctr: videoIntroController);
      }
    } else if (type != 'longPress') {
      Utils.showFavBottomSheet(context: context, ctr: videoIntroController);
    }
  }

  // 视频介绍
  showIntroDetail() {
    if (widget.loadingStatus) {
      return;
    }
    feedBack();
    // widget.showIntroDetail();
    videoIntroController.expandableCtr?.toggle();
  }

  // 用户主页
  onPushMember() {
    feedBack();
    int? mid = !widget.loadingStatus
        ? videoDetail.owner?.mid
        : videoItem['owner']?.mid;
    if (mid != null) {
      if (context.orientation == Orientation.landscape &&
          _horizontalMemberPage) {
        widget.onShowMemberPage(mid);
      } else {
        // memberHeroTag = Utils.makeHeroTag(mid);
        // String face = !loadingStatus
        //     ? videoDetail.owner!.face
        //     : videoItem['owner'].face;
        Get.toNamed(
          '/member?mid=$mid',
          // arguments: {
          //   'face': face,
          //   'heroTag': memberHeroTag,
          // },
        );
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    final ThemeData t = Theme.of(context);
    return SliverLayoutBuilder(
      builder: (BuildContext context, SliverConstraints constraints) {
        bool isHorizontal = constraints.crossAxisExtent >
            constraints.viewportMainAxisExtent * 1.25;
        return SliverPadding(
          padding: const EdgeInsets.only(
              left: StyleString.safeSpace,
              right: StyleString.safeSpace,
              top: 10),
          sliver: SliverToBoxAdapter(
              child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  Expanded(
                    child: videoItem['staff'] == null
                        ? GestureDetector(
                            onTap: onPushMember,
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              mainAxisSize: MainAxisSize.min,
                              children: [
                                NetworkImgLayer(
                                  type: 'avatar',
                                  src: widget.loadingStatus
                                      ? videoItem['owner']?.face ?? ""
                                      : videoDetail.owner!.face,
                                  width: 35,
                                  height: 35,
                                  fadeInDuration: Duration.zero,
                                  fadeOutDuration: Duration.zero,
                                ),
                                const SizedBox(width: 10),
                                Expanded(
                                  child: Column(
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: [
                                      Text(
                                        widget.loadingStatus
                                            ? videoItem['owner']?.name ?? ""
                                            : videoDetail.owner!.name,
                                        maxLines: 1,
                                        overflow: TextOverflow.ellipsis,
                                        style: TextStyle(
                                          fontSize: 13,
                                          // color: t.colorScheme.primary,
                                        ),
                                        // semanticsLabel: "UP主：${owner.name}",
                                      ),
                                      const SizedBox(height: 0),
                                      Obx(
                                        () => Text(
                                          '${Utils.numFormat(videoIntroController.userStat.value['follower'])}粉丝',
                                          style: TextStyle(
                                            fontSize: 12,
                                            color: t.colorScheme.outline,
                                          ),
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                                followButton(context, t),
                              ],
                            ),
                          )
                        : SelfSizedHorizontalList(
                            gapSize: 25,
                            itemCount: videoItem['staff'].length,
                            childBuilder: (index) => GestureDetector(
                              onTap: () {
                                int? ownerMid = !widget.loadingStatus
                                    ? videoDetail.owner?.mid
                                    : videoItem['owner']?.mid;
                                if (videoItem['staff'][index].mid == ownerMid &&
                                    context.orientation ==
                                        Orientation.landscape &&
                                    _horizontalMemberPage) {
                                  widget.onShowMemberPage(ownerMid);
                                } else {
                                  Get.toNamed(
                                    '/member?mid=${videoItem['staff'][index].mid}',
                                    // arguments: {
                                    // 'face':
                                    //     videoItem['staff'][index].face,
                                    // 'heroTag': Utils.makeHeroTag(
                                    //     videoItem['staff'][index].mid),
                                    // },
                                  );
                                }
                              },
                              child: Row(
                                children: [
                                  NetworkImgLayer(
                                    type: 'avatar',
                                    src: videoItem['staff'][index].face,
                                    width: 35,
                                    height: 35,
                                    fadeInDuration: Duration.zero,
                                    fadeOutDuration: Duration.zero,
                                  ),
                                  const SizedBox(width: 5),
                                  Column(
                                    mainAxisSize: MainAxisSize.min,
                                    crossAxisAlignment:
                                        CrossAxisAlignment.start,
                                    children: [
                                      Text(
                                        videoItem['staff'][index].name,
                                        maxLines: 1,
                                        overflow: TextOverflow.ellipsis,
                                        style: TextStyle(
                                          fontSize: 13,
                                          color: videoItem['staff'][index]
                                                          .vip
                                                          .status >
                                                      0 &&
                                                  videoItem['staff'][index]
                                                          .vip
                                                          .type ==
                                                      2
                                              ? context.vipColor
                                              : null,
                                        ),
                                      ),
                                      Text(
                                        videoItem['staff'][index].title,
                                        style: TextStyle(
                                          fontSize: 12,
                                          color: Theme.of(context)
                                              .colorScheme
                                              .outline,
                                        ),
                                      ),
                                    ],
                                  ),
                                ],
                              ),
                            ),
                          ),
                  ),
                  if (isHorizontal) ...[
                    const SizedBox(width: 10),
                    Expanded(child: actionGrid(context, videoIntroController)),
                  ]
                ],
              ),
              if (videoIntroController.videoDetail.value.argueMsg?.isNotEmpty ==
                      true &&
                  videoIntroController.showArgueMsg) ...[
                const SizedBox(height: 8),
                Container(
                  width: double.infinity,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(6),
                    color: Theme.of(context).colorScheme.secondaryContainer,
                  ),
                  padding:
                      const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
                  child: Text.rich(
                    TextSpan(children: [
                      WidgetSpan(
                        alignment: PlaceholderAlignment.middle,
                        child: Icon(
                          size: 17,
                          Icons.warning_rounded,
                          color: Theme.of(context)
                              .colorScheme
                              .onSecondaryContainer,
                        ),
                      ),
                      TextSpan(
                          text:
                              ' ${videoIntroController.videoDetail.value.argueMsg}')
                    ]),
                    style: TextStyle(
                      fontSize: 13,
                      color: Theme.of(context).colorScheme.onSecondaryContainer,
                    ),
                  ),
                )
              ],
              const SizedBox(height: 8),
              GestureDetector(
                behavior: HitTestBehavior.translucent,
                onTap: showIntroDetail,
                child: ExpandablePanel(
                  controller: videoIntroController.expandableCtr,
                  collapsed: GestureDetector(
                    onLongPress: () {
                      feedBack();
                      Utils.copyText(
                          '${videoDetail.title ?? videoItem['title'] ?? ''}');
                    },
                    child: _buildVideoTitle(),
                  ),
                  expanded: GestureDetector(
                    onLongPress: () {
                      feedBack();
                      Utils.copyText(
                          '${videoDetail.title ?? videoItem['title'] ?? ''}');
                    },
                    child: _buildVideoTitle(true),
                  ),
                  theme: const ExpandableThemeData(
                    animationDuration: Duration(milliseconds: 300),
                    scrollAnimationDuration: Duration(milliseconds: 300),
                    crossFadePoint: 0,
                    fadeCurve: Curves.ease,
                    sizeCurve: Curves.linear,
                  ),
                ),
              ),
              Stack(
                children: [
                  GestureDetector(
                    behavior: HitTestBehavior.translucent,
                    onTap: showIntroDetail,
                    child: Padding(
                      padding: const EdgeInsets.only(top: 8),
                      child: Row(
                        children: <Widget>[
                          statView(
                            context: context,
                            theme: 'gray',
                            view: !widget.loadingStatus
                                ? videoDetail.stat?.view ?? '-'
                                : videoItem['stat']?.view ?? '-',
                            size: 'medium',
                          ),
                          const SizedBox(width: 10),
                          statDanMu(
                            context: context,
                            theme: 'gray',
                            danmu: !widget.loadingStatus
                                ? videoDetail.stat?.danmu ?? '-'
                                : videoItem['stat']?.danmu ?? '-',
                            size: 'medium',
                          ),
                          const SizedBox(width: 10),
                          Text(
                            Utils.dateFormat(
                                !widget.loadingStatus
                                    ? videoDetail.pubdate
                                    : videoItem['pubdate'],
                                formatType: 'detail'),
                            style: TextStyle(
                              fontSize: 12,
                              color: t.colorScheme.outline,
                            ),
                          ),
                          if (MineController.anonymity.value) ...<Widget>[
                            const SizedBox(width: 10),
                            Icon(
                              MdiIcons.incognito,
                              size: 15,
                              color: t.colorScheme.outline,
                              semanticLabel: '无痕',
                            ),
                          ],
                          const SizedBox(width: 10),
                          if (videoIntroController.isShowOnlineTotal)
                            Obx(
                              () => Text(
                                '${videoIntroController.total.value}人在看',
                                style: TextStyle(
                                  fontSize: 12,
                                  color: t.colorScheme.outline,
                                ),
                              ),
                            ),
                        ],
                      ),
                    ),
                  ),
                  if (videoIntroController.enableAi)
                    Positioned(
                      right: 10,
                      top: 0,
                      bottom: 0,
                      child: Center(
                        child: Semantics(
                          label: 'AI总结',
                          child: GestureDetector(
                            onTap: () async {
                              final res =
                                  await videoIntroController.aiConclusion();
                              if (res['status']) {
                                widget.showAiBottomSheet();
                              }
                            },
                            child:
                                Image.asset('assets/images/ai.png', height: 22),
                          ),
                        ),
                      ),
                    )
                ],
              ),
              GestureDetector(
                behavior: HitTestBehavior.translucent,
                onTap: showIntroDetail,
                child: ExpandablePanel(
                  controller: videoIntroController.expandableCtr,
                  collapsed: const SizedBox.shrink(),
                  expanded: Column(
                    mainAxisSize: MainAxisSize.min,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      const SizedBox(height: 8),
                      GestureDetector(
                        onTap: () {
                          Utils.copyText(
                              '${videoIntroController.videoDetail.value.bvid}');
                        },
                        child: Text(
                          videoIntroController.videoDetail.value.bvid ?? '',
                          style: TextStyle(
                            fontSize: 14,
                            color: Theme.of(context).colorScheme.primary,
                          ),
                        ),
                      ),
                      if (videoIntroController
                          .videoDetail.value.descV2.isNullOrEmpty.not) ...[
                        const SizedBox(height: 8),
                        SelectableText.rich(
                          style: const TextStyle(
                            height: 1.4,
                            // fontSize: 13,
                          ),
                          TextSpan(
                            children: [
                              buildContent(context,
                                  videoIntroController.videoDetail.value),
                            ],
                          ),
                        ),
                      ],
                      if (videoIntroController.videoTags is List &&
                          videoIntroController.videoTags.isNotEmpty) ...[
                        const SizedBox(height: 8),
                        Wrap(
                          spacing: 8,
                          runSpacing: 8,
                          children: (videoIntroController.videoTags as List)
                              .map(
                                (item) => SearchText(
                                  fontSize: 13,
                                  text: item['tag_name'],
                                  onTap: (_) => Get.toNamed('/searchResult',
                                      parameters: {
                                        'keyword': item['tag_name']
                                      }),
                                  onLongPress: (_) =>
                                      Utils.copyText(item['tag_name']),
                                ),
                              )
                              .toList(),
                        ),
                      ],
                    ],
                  ),
                  theme: const ExpandableThemeData(
                    animationDuration: Duration(milliseconds: 300),
                    scrollAnimationDuration: Duration(milliseconds: 300),
                    crossFadePoint: 0,
                    fadeCurve: Curves.ease,
                    sizeCurve: Curves.linear,
                  ),
                ),
              ),
              Obx(
                () => videoIntroController.queryVideoIntroData.value["status"]
                    ? const SizedBox.shrink()
                    : Center(
                        child: TextButton.icon(
                          icon: const Icon(Icons.refresh),
                          onPressed: () {
                            videoIntroController
                                .queryVideoIntroData.value["status"] = true;
                            videoIntroController.queryVideoIntro();
                            if (videoDetailCtr.videoUrl.isNullOrEmpty &&
                                videoDetailCtr.isQuerying.not) {
                              videoDetailCtr.queryVideoUrl();
                            }
                          },
                          label: const Text("点此重新加载"),
                        ),
                      ),
              ),
              // 点赞收藏转发 布局样式1
              // SingleChildScrollView(
              //   padding: const EdgeInsets.only(top: 7, bottom: 7),
              //   scrollDirection: Axis.horizontal,
              //   child: actionRow(
              //     context,
              //     videoIntroController,
              //     videoDetailCtr,
              //   ),
              // ),
              // 点赞收藏转发 布局样式2
              if (!isHorizontal) ...[
                const SizedBox(height: 8),
                actionGrid(context, videoIntroController),
              ],
              // 合集
              if (!widget.loadingStatus &&
                  videoDetail.ugcSeason != null &&
                  (context.orientation != Orientation.landscape ||
                      (context.orientation == Orientation.landscape &&
                          videoDetailCtr.horizontalSeasonPanel.not)))
                SeasonPanel(
                  heroTag: widget.heroTag,
                  ugcSeason: videoDetail.ugcSeason!,
                  changeFuc: videoIntroController.changeSeasonOrbangu,
                  showEpisodes: widget.showEpisodes,
                  pages: videoDetail.pages,
                  videoIntroController: videoIntroController,
                ),
              if (!widget.loadingStatus &&
                  videoDetail.pages != null &&
                  videoDetail.pages!.length > 1 &&
                  (context.orientation != Orientation.landscape ||
                      (context.orientation == Orientation.landscape &&
                          videoDetailCtr.horizontalSeasonPanel.not))) ...[
                PagesPanel(
                  heroTag: widget.heroTag,
                  videoIntroController: videoIntroController,
                  bvid: videoIntroController.bvid,
                  changeFuc: videoIntroController.changeSeasonOrbangu,
                  showEpisodes: widget.showEpisodes,
                ),
              ],
            ],
          )),
        );
      },
    );
  }

  Obx followButton(BuildContext context, ThemeData t) {
    return Obx(
      () {
        int attr = videoIntroController.followStatus['attribute'] ?? 0;
        return TextButton(
          onPressed: () => videoIntroController.actionRelationMod(context),
          style: TextButton.styleFrom(
            visualDensity: const VisualDensity(vertical: -3),
            foregroundColor: attr != 0
                ? t.colorScheme.outline
                : t.colorScheme.onSecondaryContainer,
            backgroundColor: attr != 0
                ? t.colorScheme.onInverseSurface
                : t.colorScheme.secondaryContainer,
          ),
          child: Text(
            attr == 128
                ? '已拉黑'
                : attr != 0
                    ? '已关注'
                    : '关注',
            style: TextStyle(fontSize: t.textTheme.labelMedium!.fontSize),
          ),
        );
      },
    );
  }

  Widget actionGrid(BuildContext context, videoIntroController) {
    return LayoutBuilder(
        builder: (BuildContext context, BoxConstraints constraints) {
      return Container(
        margin: const EdgeInsets.only(top: 1),
        height: 48,
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            Obx(
              () => ActionItem(
                icon: const Icon(FontAwesomeIcons.thumbsUp),
                selectIcon: const Icon(FontAwesomeIcons.solidThumbsUp),
                onTap: () => handleState(videoIntroController.actionLikeVideo),
                onLongPress: () =>
                    handleState(videoIntroController.actionOneThree),
                selectStatus: videoIntroController.hasLike.value,
                loadingStatus: widget.loadingStatus,
                semanticsLabel: '点赞',
                text: !widget.loadingStatus
                    ? Utils.numFormat(videoDetail.stat!.like!)
                    : '-',
                needAnim: true,
                hasOneThree: videoIntroController.hasLike.value &&
                    videoIntroController.hasCoin.value &&
                    videoIntroController.hasFav.value,
                callBack: (start) {
                  if (start) {
                    _coinKey.currentState?.controller?.forward();
                    _favKey.currentState?.controller?.forward();
                  } else {
                    _coinKey.currentState?.controller?.reverse();
                    _favKey.currentState?.controller?.reverse();
                  }
                },
              ),
            ),
            Obx(
              () => ActionItem(
                  icon: const Icon(FontAwesomeIcons.thumbsDown),
                  selectIcon: const Icon(FontAwesomeIcons.solidThumbsDown),
                  onTap: () =>
                      handleState(videoIntroController.actionDislikeVideo),
                  selectStatus: videoIntroController.hasDislike.value,
                  loadingStatus: widget.loadingStatus,
                  semanticsLabel: '点踩',
                  text: "点踩"),
            ),
            // ActionItem(
            //     icon: const Icon(FontAwesomeIcons.clock),
            //     onTap: () => videoIntroController.actionShareVideo(),
            //     selectStatus: false,
            //     loadingStatus: loadingStatus,
            //     text: '稍后再看'),
            Obx(
              () => ActionItem(
                key: _coinKey,
                icon: const Icon(FontAwesomeIcons.b),
                selectIcon: const Icon(FontAwesomeIcons.b),
                onTap: () => handleState(videoIntroController.actionCoinVideo),
                selectStatus: videoIntroController.hasCoin.value,
                loadingStatus: widget.loadingStatus,
                semanticsLabel: '投币',
                text: !widget.loadingStatus
                    ? Utils.numFormat(videoDetail.stat!.coin!)
                    : '-',
                needAnim: true,
              ),
            ),
            Obx(
              () => ActionItem(
                key: _favKey,
                icon: const Icon(FontAwesomeIcons.star),
                selectIcon: const Icon(FontAwesomeIcons.solidStar),
                onTap: () => showFavBottomSheet(),
                onLongPress: () => showFavBottomSheet(type: 'longPress'),
                selectStatus: videoIntroController.hasFav.value,
                loadingStatus: widget.loadingStatus,
                semanticsLabel: '收藏',
                text: !widget.loadingStatus
                    ? Utils.numFormat(videoDetail.stat!.favorite!)
                    : '-',
                needAnim: true,
              ),
            ),
            ActionItem(
                icon: const Icon(FontAwesomeIcons.comment),
                onTap: () => videoDetailCtr.tabCtr
                    .animateTo(videoDetailCtr.tabCtr.index == 1 ? 0 : 1),
                selectStatus: false,
                loadingStatus: widget.loadingStatus,
                semanticsLabel: '评论',
                text: !widget.loadingStatus
                    ? Utils.numFormat(videoDetail.stat!.reply!)
                    : '评论'),
            ActionItem(
                icon: const Icon(FontAwesomeIcons.shareFromSquare),
                onTap: () => videoIntroController.actionShareVideo(),
                selectStatus: false,
                loadingStatus: widget.loadingStatus,
                semanticsLabel: '分享',
                text: !widget.loadingStatus
                    ? Utils.numFormat(videoDetail.stat!.share!)
                    : '分享'),
          ],
        ),
      );
    });
  }

  Widget actionRow(BuildContext context, videoIntroController, videoDetailCtr) {
    return Row(children: <Widget>[
      Obx(
        () => ActionRowItem(
          icon: const Icon(FontAwesomeIcons.thumbsUp),
          onTap: () => handleState(videoIntroController.actionLikeVideo),
          selectStatus: videoIntroController.hasLike.value,
          loadingStatus: widget.loadingStatus,
          text:
              !widget.loadingStatus ? videoDetail.stat!.like!.toString() : '-',
        ),
      ),
      const SizedBox(width: 8),
      Obx(
        () => ActionRowItem(
          icon: const Icon(FontAwesomeIcons.b),
          onTap: () => handleState(videoIntroController.actionCoinVideo),
          selectStatus: videoIntroController.hasCoin.value,
          loadingStatus: widget.loadingStatus,
          text:
              !widget.loadingStatus ? videoDetail.stat!.coin!.toString() : '-',
        ),
      ),
      const SizedBox(width: 8),
      Obx(
        () => ActionRowItem(
          icon: const Icon(FontAwesomeIcons.heart),
          onTap: () => showFavBottomSheet(),
          onLongPress: () => showFavBottomSheet(type: 'longPress'),
          selectStatus: videoIntroController.hasFav.value,
          loadingStatus: widget.loadingStatus,
          text: !widget.loadingStatus
              ? videoDetail.stat!.favorite!.toString()
              : '-',
        ),
      ),
      const SizedBox(width: 8),
      ActionRowItem(
        icon: const Icon(FontAwesomeIcons.comment),
        onTap: () {
          videoDetailCtr.tabCtr.animateTo(1);
        },
        selectStatus: false,
        loadingStatus: widget.loadingStatus,
        text: !widget.loadingStatus ? videoDetail.stat!.reply!.toString() : '-',
      ),
      const SizedBox(width: 8),
      ActionRowItem(
          icon: const Icon(FontAwesomeIcons.share),
          onTap: () => videoIntroController.actionShareVideo(),
          selectStatus: false,
          loadingStatus: widget.loadingStatus,
          // text: !loadingStatus
          //     ? videoDetail.stat!.share!.toString()
          //     : '-',
          text: '转发'),
    ]);
  }

  InlineSpan buildContent(BuildContext context, VideoDetailData content) {
    final List descV2 = content.descV2!;
    // type
    // 1 普通文本
    // 2 @用户
    final List<TextSpan> spanChildren = List.generate(descV2.length, (index) {
      final currentDesc = descV2[index];
      switch (currentDesc.type) {
        case 1:
          final List<InlineSpan> spanChildren = <InlineSpan>[];
          final RegExp urlRegExp =
              RegExp(r'https?://\S+\b|av\d+|bv\S+\b', caseSensitive: false);

          (currentDesc.rawText as String).splitMapJoin(
            urlRegExp,
            onMatch: (Match match) {
              String matchStr = match[0]!;
              if (RegExp(r'^av\d+$', caseSensitive: false).hasMatch(matchStr)) {
                try {
                  // validate
                  int aid = int.parse(matchStr.substring(2));
                  IdUtils.av2bv(aid);
                  spanChildren.add(
                    TextSpan(
                      text: matchStr,
                      style: TextStyle(
                          color: Theme.of(context).colorScheme.primary),
                      recognizer: TapGestureRecognizer()
                        ..onTap = () {
                          PiliScheme.videoPush(aid, null);
                        },
                    ),
                  );
                } catch (e) {
                  spanChildren.add(TextSpan(text: matchStr));
                }
              } else if (RegExp(r'^bv\S+\b$', caseSensitive: false)
                  .hasMatch(matchStr)) {
                try {
                  // validate
                  IdUtils.bv2av(matchStr);
                  spanChildren.add(
                    TextSpan(
                      text: matchStr,
                      style: TextStyle(
                          color: Theme.of(context).colorScheme.primary),
                      recognizer: TapGestureRecognizer()
                        ..onTap = () {
                          PiliScheme.videoPush(null, matchStr);
                        },
                    ),
                  );
                } catch (e) {
                  spanChildren.add(TextSpan(text: matchStr));
                }
              } else {
                spanChildren.add(
                  TextSpan(
                    text: matchStr,
                    style:
                        TextStyle(color: Theme.of(context).colorScheme.primary),
                    recognizer: TapGestureRecognizer()
                      ..onTap = () {
                        try {
                          Utils.handleWebview(matchStr);
                        } catch (err) {
                          SmartDialog.showToast(err.toString());
                        }
                      },
                  ),
                );
              }
              return '';
            },
            onNonMatch: (String nonMatchStr) {
              spanChildren.add(TextSpan(text: nonMatchStr));
              return '';
            },
          );
          return TextSpan(children: spanChildren);
        case 2:
          final Color colorSchemePrimary =
              Theme.of(context).colorScheme.primary;
          final String heroTag = Utils.makeHeroTag(currentDesc.bizId);
          return TextSpan(
            text: '@${currentDesc.rawText}',
            style: TextStyle(color: colorSchemePrimary),
            recognizer: TapGestureRecognizer()
              ..onTap = () {
                Get.toNamed(
                  '/member?mid=${currentDesc.bizId}',
                  arguments: {'face': '', 'heroTag': heroTag},
                );
              },
          );
        default:
          return const TextSpan();
      }
    });
    return TextSpan(children: spanChildren);
  }
}
