import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:logging/logging.dart';
import 'package:provider/provider.dart';
import 'package:relatica/utils/snackbar_builder.dart';
import 'package:result_monad/result_monad.dart';

import '../../globals.dart';
import '../../models/filters/timeline_entry_filter.dart';
import '../../models/flattened_tree_item.dart';
import '../../models/timeline_entry.dart';
import '../../services/auth_service.dart';
import '../../services/timeline_entry_filter_service.dart';
import '../../services/timeline_manager.dart';
import '../../utils/active_profile_selector.dart';
import '../../utils/clipboard_utils.dart';
import '../../utils/filter_runner.dart';
import '../../utils/html_to_edit_text_helper.dart';
import '../../utils/responsive_sizes_calculator.dart';
import '../../utils/url_opening_utils.dart';
import '../html_text_viewer_control.dart';
import '../media_attachment_viewer_control.dart';
import '../padding.dart';
import 'interactions_bar_control.dart';
import 'link_preview_control.dart';
import 'status_header_control.dart';

class FlattenedTreeEntryControl extends StatefulWidget {
  final FlattenedTreeItem originalItem;
  final bool openRemote;
  final bool showStatusOpenButton;

  const FlattenedTreeEntryControl(
      {super.key,
      required this.originalItem,
      required this.openRemote,
      required this.showStatusOpenButton});

  @override
  State<FlattenedTreeEntryControl> createState() => _StatusControlState();
}

class _StatusControlState extends State<FlattenedTreeEntryControl> {
  static final _logger = Logger('$FlattenedTreeEntryControl');

  var showContent = true;
  var showFilteredPost = false;
  var showComments = false;
  var isProcessing = false;

  FlattenedTreeItem get item => widget.originalItem;

  TimelineEntry get entry => item.timelineEntry;

  bool get isPost => entry.parentId.isEmpty;

  bool get hasComments => entry.engagementSummary.repliesCount > 0;

  var filteringInfo = FilterResult.show;

  @override
  void initState() {
    super.initState();
    showContent = entry.spoilerText.isEmpty;
    showComments = isPost ? false : true;
  }

  @override
  Widget build(BuildContext context) {
    _logger.finest('Building ${entry.toShortString()}');
    final filterService = context
        .watch<ActiveProfileSelector<TimelineEntryFilterService>>()
        .activeEntry
        .value;

    filteringInfo = filterService.checkTimelineEntry(entry);

    const otherPadding = 8.0;
    final leftPadding = otherPadding + (widget.originalItem.level * 15.0);
    final color = widget.originalItem.level.isOdd
        ? Theme.of(context).secondaryHeaderColor
        : Theme.of(context).dialogBackgroundColor;

    if (filteringInfo.isFiltered &&
        filteringInfo.action == TimelineEntryFilterAction.hide) {
      return kReleaseMode
          ? const SizedBox()
          : Container(
              height: 10,
              color: Colors.red,
            );
    }

    late final Widget body;
    if (filteringInfo.isFiltered && !showFilteredPost) {
      body = buildHiddenBody(context, filteringInfo);
    } else {
      body = buildMainWidgetBody(context);
    }

    final bodyCard = Container(
      decoration: BoxDecoration(
        color: color,
        border: Border.all(width: 0.5),
        borderRadius: BorderRadius.circular(5.0),
        boxShadow: [
          BoxShadow(
            color: Theme.of(context).dividerColor,
            blurRadius: 2,
            offset: const Offset(4, 4),
            spreadRadius: 0.1,
            blurStyle: BlurStyle.normal,
          )
        ],
      ),
      child: body,
    );
    return Padding(
      padding: EdgeInsets.only(
        left: leftPadding,
        right: otherPadding,
        top: otherPadding,
        bottom: otherPadding,
      ),
      child: GestureDetector(
          onTap: () {
            if (widget.showStatusOpenButton) {
              _goToPostView();
            }
          },
          child: bodyCard),
    );
  }

  Widget buildMainWidgetBody(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(5.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            children: [
              Expanded(
                child: StatusHeaderControl(
                  entry: entry,
                ),
              ),
              if (filteringInfo.isFiltered)
                IconButton(
                    onPressed: () => setState(() {
                          showFilteredPost = false;
                        }),
                    icon: const Icon(Icons.hide_source)),
              buildMenuControl(context),
            ],
          ),
          const VerticalPadding(
            height: 5,
          ),
          if (entry.spoilerText.isNotEmpty)
            TextButton(
                onPressed: () {
                  setState(() {
                    showContent = !showContent;
                  });
                },
                child: Text(
                    'Content Summary: ${entry.spoilerText} (Click to ${showContent ? "Hide" : "Show"}}')),
          if (showContent) ...[
            buildContentField(context),
            const VerticalPadding(
              height: 5,
            ),
            if (entry.linkPreviewData != null)
              LinkPreviewControl(preview: entry.linkPreviewData!),
            buildMediaBar(context),
          ],
          const VerticalPadding(
            height: 5,
          ),
          InteractionsBarControl(
            entry: entry,
            isMine: item.isMine,
            showOpenControl: widget.showStatusOpenButton,
          ),
          const VerticalPadding(
            height: 5,
          ),
        ],
      ),
    );
  }

  Widget buildHiddenBody(BuildContext context, FilterResult result) {
    return Padding(
      padding: const EdgeInsets.all(5.0),
      child: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          if (result.isFiltered &&
              result.action == TimelineEntryFilterAction.warn)
            TextButton(
              onPressed: () {
                setState(() {
                  showFilteredPost = true;
                });
              },
              child: Text(
                  '${result.trippingFilterName} filtered post. Click to show'),
            ),
        ],
      ),
    );
  }

  Widget buildContentField(BuildContext context) {
    return HtmlTextViewerControl(
      content: entry.body,
      onTapUrl: (url) async =>
          await openUrlStringInSystembrowser(context, url, 'link'),
    );
  }

  Widget buildMediaBar(BuildContext context) {
    final items = entry.mediaAttachments;
    if (items.isEmpty) {
      return const SizedBox();
    }

    // A Link Preview with only one media attachment will have a duplicate image
    // even though it points to different resources server side. So we don't
    // want to render it twice.
    if (entry.linkPreviewData != null && items.length == 1) {
      return const SizedBox();
    }

    // A Diaspora reshare will have an HTML-built card with a link preview image
    // to the same image as what would be in the single attachment but at a
    // different link. So we don't want it to render twice.
    final linkPhotoBaseUrl = Uri.https(
      context.read<AccountsService>().currentProfile.serverName,
      'photo/link',
    ).toString();
    if (entry.body.contains(linkPhotoBaseUrl) && items.length == 1) {
      return const SizedBox();
    }

    return SizedBox(
        height: ResponsiveSizesCalculator(context).maxThumbnailHeight,
        child: ListView.separated(
            scrollDirection: Axis.horizontal,
            itemBuilder: (context, index) {
              return MediaAttachmentViewerControl(
                attachments: items,
                index: index,
                width: items.length > 1
                    ? ResponsiveSizesCalculator(context).maxThumbnailWidth
                    : ResponsiveSizesCalculator(context).viewPortalWidth,
                height: ResponsiveSizesCalculator(context).maxThumbnailHeight,
              );
            },
            separatorBuilder: (context, index) {
              return const HorizontalPadding();
            },
            itemCount: items.length));
  }

  Widget buildMenuControl(BuildContext context) {
    const editStatus = 'Edit';
    const deleteStatus = 'Delete';
    const divider = 'Divider';
    const goToPost = 'Open Post';
    const copyText = 'Copy Post Text';
    const copyUrl = 'Copy URL';
    const openExternal = 'Open In Browser';
    const showLikers = 'Show Likers';
    const showResharers = 'Show Reshares';
    final options = [
      if (widget.showStatusOpenButton && !widget.openRemote) goToPost,
      if (item.isMine && !item.timelineEntry.youReshared) editStatus,
      if (item.isMine) deleteStatus,
      divider,
      showLikers,
      showResharers,
      divider,
      openExternal,
      copyUrl,
      copyText,
    ];

    if (options.first == divider) {
      options.removeAt(0);
    }

    final entry = widget.originalItem.timelineEntry;

    return PopupMenuButton<String>(onSelected: (menuOption) async {
      if (!mounted) {
        return;
      }

      switch (menuOption) {
        case goToPost:
          _goToPostView();
          break;
        case editStatus:
          if (item.timelineEntry.parentId.isEmpty) {
            context.push('/post/edit/${item.timelineEntry.id}');
          } else {
            context.push('/comment/edit/${item.timelineEntry.id}');
          }
          break;
        case deleteStatus:
          deleteEntry();
          break;
        case openExternal:
          await openUrlStringInSystembrowser(
            context,
            item.timelineEntry.externalLink,
            'Post',
          );
          break;
        case copyUrl:
          await copyToClipboard(
            context: context,
            text: item.timelineEntry.externalLink,
            message: 'Post link copied to clipboard',
          );
          break;
        case copyText:
          await copyToClipboard(
            context: context,
            text: htmlToSimpleText(item.timelineEntry.body),
            message: 'Post link copied to clipboard',
          );
          break;
        case showLikers:
          await context.push('/likes/${entry.id}');
          break;
        case showResharers:
          await context.push('/reshares/${entry.id}');
          break;
        default:
        //do nothing
      }
    }, itemBuilder: (context) {
      return options
          .map(
            (o) => PopupMenuItem(
              value: o,
              enabled: switch (o) {
                divider => false,
                showResharers => entry.engagementSummary.rebloggedCount > 0,
                showLikers => entry.engagementSummary.favoritesCount > 0,
                _ => true,
              },
              child: o == divider ? const Divider() : Text(o),
            ),
          )
          .toList();
    });
  }

  Future<void> deleteEntry() async {
    setState(() {
      isProcessing = true;
    });
    final confirm =
        await showYesNoDialog(context, 'Delete ${isPost ? "Post" : "Comment"}');
    if (confirm == true) {
      await getIt<ActiveProfileSelector<TimelineManager>>()
          .activeEntry
          .transformAsync(
              (tm) async => await tm.deleteEntryById(item.timelineEntry.id))
          .match(onSuccess: (_) {
        isProcessing = false;
        if (context.canPop()) {
          context.pop();
        }
      }, onError: (e) {
        isProcessing = false;
        buildSnackbar(
          context,
          'Error deleting ${isPost ? "Post" : "Comment"}: $e',
        );
      });
    }
    setState(() {});
  }

  void _goToPostView() {
    context
        .push('/post/view/${item.timelineEntry.id}/${item.timelineEntry.id}');
  }
}
