import 'dart:math';

import 'package:flutter/material.dart';
import 'package:lemmy_api_client/v3.dart';
import 'package:nested/nested.dart';

import '../../comment_tree.dart';
import '../../l10n/l10n.dart';
import '../../stores/config_store.dart';
import '../../util/async_store_listener.dart';
import '../../util/extensions/api.dart';
import '../../util/goto.dart';
import '../../util/mobx_provider.dart';
import '../../util/observer_consumers.dart';
import '../../util/text_color.dart';
import '../avatar.dart';
import '../info_table_popup.dart';
import '../markdown_text.dart';
import 'comment_actions.dart';
import 'comment_store.dart';

/// A single comment that renders its replies
class CommentWidget extends StatelessWidget {
  final CommentTree commentTree;
  final int? userMentionId;
  final int depth;
  final bool canBeMarkedAsRead;
  final bool detached;
  final bool hideOnRead;

  const CommentWidget(
    this.commentTree, {
    this.depth = 0,
    this.detached = false,
    this.canBeMarkedAsRead = false,
    this.hideOnRead = false,
    this.userMentionId,
    super.key,
  });

  CommentWidget.fromCommentView(
    CommentView cv, {
    bool canBeMarkedAsRead = false,
    bool hideOnRead = false,
    bool detached = true,
    Key? key,
  }) : this(
          CommentTree(cv),
          detached: detached,
          canBeMarkedAsRead: canBeMarkedAsRead,
          hideOnRead: hideOnRead,
          key: key,
        );

  CommentWidget.fromPersonMentionView(
    PersonMentionView userMentionView, {
    bool hideOnRead = false,
    Key? key,
  }) : this(
          CommentTree(CommentView.fromJson(userMentionView.toJson())),
          hideOnRead: hideOnRead,
          canBeMarkedAsRead: true,
          detached: true,
          userMentionId: userMentionView.personMention.id,
          key: key,
        );

  static void showCommentInfo(BuildContext context, CommentView commentView) {
    final percentOfUpvotes = 100 *
        (commentView.counts.upvotes /
            (commentView.counts.upvotes + commentView.counts.downvotes));

    showInfoTablePopup(context: context, table: {
      ...commentView.toJson(),
      '% of upvotes': '$percentOfUpvotes%',
    });
  }

  @override
  Widget build(BuildContext context) {
    return MobxProvider(
      create: (context) => CommentStore(
        context.read(),
        commentTree: commentTree,
        userMentionId: userMentionId,
        depth: depth,
        canBeMarkedAsRead: canBeMarkedAsRead,
        detached: detached,
        hideOnRead: hideOnRead,
      ),
      builder: (context, child) => Nested(
        children: [
          AsyncStoreListener<BlockedPerson>(
            asyncStore: context.read<CommentStore>().blockingState,
            successMessageBuilder: (context, state) {
              final name = state.personView.person.preferredName;
              return state.blocked ? '$name blocked' : '$name unblocked';
            },
          ),
          AsyncStoreListener(
            asyncStore: context.read<CommentStore>().votingState,
          ),
          AsyncStoreListener(
            asyncStore: context.read<CommentStore>().deletingState,
          ),
          AsyncStoreListener(
            asyncStore: context.read<CommentStore>().savingState,
          ),
          AsyncStoreListener<CommentReportView>(
            asyncStore: context.read<CommentStore>().reportingState,
            successMessageBuilder: (context, data) => 'Comment reported',
          ),
        ],
        child: const _CommentWidget(),
      ),
    );
  }
}

class _CommentWidget extends StatelessWidget {
  static const colors = [
    Colors.pink,
    Colors.green,
    Colors.amber,
    Colors.cyan,
    Colors.indigo,
  ];

  static const indentWidth = 5.0;

  const _CommentWidget();

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);

    final body = ObserverBuilder<CommentStore>(
      builder: (context, store) {
        final comment = store.comment.comment;

        if (comment.deleted) {
          return Text(
            L10n.of(context).deleted_by_creator,
            style: const TextStyle(fontStyle: FontStyle.italic),
          );
        } else if (comment.removed) {
          return const Text(
            'comment deleted by moderator',
            style: TextStyle(fontStyle: FontStyle.italic),
          );
        } else if (store.collapsed) {
          return Opacity(
            opacity: 0.3,
            child: Text(
              comment.content,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
          );
        }

        return store.showRaw
            ? store.selectable
                ? SelectableText(comment.content)
                : Text(comment.content)
            : MarkdownText(
                comment.content,
                instanceHost: comment.instanceHost,
                selectable: store.selectable,
              );
      },
    );

    return ObserverBuilder<CommentStore>(
      builder: (context, store) {
        if (store.hideOnRead && store.comment.comment.read) {
          return const SizedBox();
        }

        final comment = store.comment.comment;
        final creator = store.comment.creator;

        return InkWell(
          onLongPress: store.selectable ? null : store.toggleCollapsed,
          child: Column(
            children: [
              Container(
                padding: const EdgeInsets.all(10),
                margin: EdgeInsets.only(
                  left: max((store.depth - 1) * indentWidth, 0),
                ),
                decoration: BoxDecoration(
                  border: Border(
                    left: store.depth > 0
                        ? BorderSide(
                            color: colors[store.depth % colors.length],
                            width: indentWidth,
                          )
                        : BorderSide.none,
                    top: const BorderSide(width: 0.2),
                  ),
                ),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Row(children: [
                      if (creator.avatar != null)
                        Padding(
                          padding: const EdgeInsets.only(right: 5),
                          child: InkWell(
                            onTap: () =>
                                goToUser.fromPersonSafe(context, creator),
                            child: Avatar(
                              url: creator.avatar,
                              radius: 10,
                              noBlank: true,
                            ),
                          ),
                        ),
                      InkWell(
                        onTap: () => goToUser.fromPersonSafe(context, creator),
                        child: Text(
                          creator.originPreferredName,
                          style: TextStyle(
                            color: theme.colorScheme.secondary,
                          ),
                        ),
                      ),
                      if (creator.isCakeDay) const Text(' 🍰'),
                      if (store.isOP)
                        _CommentTag('OP', theme.colorScheme.secondary),
                      if (creator.admin)
                        _CommentTag(
                          L10n.of(context).admin.toUpperCase(),
                          theme.colorScheme.secondary,
                        ),
                      if (creator.banned)
                        const _CommentTag('BANNED', Colors.red),
                      if (store.comment.creatorBannedFromCommunity)
                        const _CommentTag('BANNED FROM COMMUNITY', Colors.red),
                      const Spacer(),
                      if (store.collapsed && store.children.isNotEmpty) ...[
                        _CommentTag(
                          '+${store.children.length}',
                          Theme.of(context).colorScheme.secondary,
                        ),
                        const SizedBox(width: 7),
                      ],
                      InkWell(
                        onTap: () => CommentWidget.showCommentInfo(
                          context,
                          store.comment,
                        ),
                        child: Consumer<ConfigStore>(
                          builder: (context, configStore, child) {
                            return ObserverBuilder<CommentStore>(
                              builder: (context, store) => Row(
                                children: [
                                  if (store.votingState.isLoading)
                                    SizedBox.fromSize(
                                      size: const Size.square(16),
                                      child: const CircularProgressIndicator
                                          .adaptive(),
                                    )
                                  else if (configStore.showScores)
                                    Text(
                                      store.comment.counts.score
                                          .compact(context),
                                    ),
                                  if (configStore.showScores)
                                    const Text(' · ')
                                  else
                                    const SizedBox(width: 4),
                                  Text(comment.published.timeago(context)),
                                ],
                              ),
                            );
                          },
                        ),
                      )
                    ]),
                    const SizedBox(height: 10),
                    body,
                    const SizedBox(height: 5),
                    const CommentActions(),
                  ],
                ),
              ),
              if (!store.collapsed)
                for (final c in store.children)
                  CommentWidget(c, depth: store.depth + 1),
            ],
          ),
        );
      },
    );
  }
}

class _CommentTag extends StatelessWidget {
  final String text;
  final Color backgroundColor;

  const _CommentTag(this.text, this.backgroundColor);

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(left: 5),
      child: Container(
        decoration: BoxDecoration(
          borderRadius: const BorderRadius.all(Radius.circular(5)),
          color: backgroundColor,
        ),
        padding: const EdgeInsets.symmetric(horizontal: 3, vertical: 2),
        child: Text(
          text,
          style: TextStyle(
            color: textColorBasedOnBackground(backgroundColor),
            fontSize: Theme.of(context).textTheme.bodyText1!.fontSize! - 5,
            fontWeight: FontWeight.w800,
          ),
        ),
      ),
    );
  }
}
