import APIClient
import ComponentLibrary
import ComposableArchitecture
import Localization
import StatsigClient
import SwiftUI
import Utilities

struct CommentThreadItem: View, Equatable {
    let comment: ClipComment
    let isCommentByCurrentUser: Bool
    let isCommentByClipAuthor: Bool
    let isClipByCurrentUser: Bool
    let isLoading: Bool
    /*
        It can be both first and last reply

        When it is first and last we show the
        count of replies instead of load more
        as "Read (x) replies"
     */
    let parentReplyCount: Int
    let isFirstReply: Bool
    let isLastReply: Bool
    let hasMoreReplies: Bool
    let hasExpandedLongComment: Bool
    let tapAuthor: () -> Void
    let tapMentionedUser: (String) -> Void
    let tapReaction: () -> Void
    let tapReplyAction: () -> Void
    let tapTrackTimestamp: (Double) -> Void
    let reportAction: (ReportCommentRequest.Reason) -> Void
    let deleteAction: () -> Void
    let tapLoadMoreReplies: () -> Void
    let tapExpandOnLongComment: () -> Void

    // In Lazy Container views this happens
    // as view is added to hierarchy
    let onAppear: () -> Void

    @State var isMoreMenuDisplayed: Bool = false

    @State private var showingReplyReasonSheet = false
    @State private var reportSheetContentHeight = CGFloat.zero

    init(_ comment: ClipComment,
         isCommentByCurrentUser: Bool,
         isCommentByClipAuthor: Bool = false,
         isClipByCurrentUser: Bool,
         isLoading: Bool = false,
         parentReplyCount: Int = .zero,
         isFirstReply: Bool = false,
         isLastReply: Bool = false,
         hasMoreReplies: Bool = false,
         hasExpandedLongComment: Bool = false,
         tapAuthor: @escaping () -> Void = {},
         tapMentionedUser: @escaping (String) -> Void = { _ in },
         tapReaction: @escaping () -> Void = {},
         tapReplyAction: @escaping () -> Void = {},
         tapTrackTimestamp: @escaping (Double) -> Void = { _ in },
         tapLoadMoreReplies: @escaping () -> Void = {},
         tapExpandOnLongComment: @escaping () -> Void = {},
         reportAction: @escaping (ReportCommentRequest.Reason) -> Void = { _ in },
         deleteAction: @escaping () -> Void = {},
         onAppear: @escaping () -> Void = {})
    {
        self.comment = comment
        self.isCommentByCurrentUser = isCommentByCurrentUser
        self.isCommentByClipAuthor = isCommentByClipAuthor
        self.isClipByCurrentUser = isClipByCurrentUser
        self.isLoading = isLoading
        self.parentReplyCount = parentReplyCount
        self.isFirstReply = isFirstReply
        self.isLastReply = isLastReply
        self.hasMoreReplies = hasMoreReplies
        self.hasExpandedLongComment = hasExpandedLongComment
        self.tapAuthor = tapAuthor
        self.tapMentionedUser = tapMentionedUser
        self.tapReaction = tapReaction
        self.tapReplyAction = tapReplyAction
        self.tapTrackTimestamp = tapTrackTimestamp
        self.tapLoadMoreReplies = tapLoadMoreReplies
        self.tapExpandOnLongComment = tapExpandOnLongComment
        self.reportAction = reportAction
        self.deleteAction = deleteAction
        self.onAppear = onAppear
    }

    private var showingTrackTimestamp: Bool {
        !comment.isReply && comment.trackTimestamp >= 1
    }

    var body: some View {
        ZStack {
            HStack(alignment: .top) {
                Group {
                    Button {
                        tapAuthor()
                    } label: {
                        avatarImage
                    }

                    mainContentAndTitles
                }
                .opacity(isMoreMenuDisplayed ? 0.25 : 1.0)
                Spacer()

                if isLoading {
                    ProgressView()
                        .progressViewStyle(.circular)
                } else {
                    rightSideButtons
                        .animation(.none, value: isMoreMenuDisplayed)
                }
            }
            if isMoreMenuDisplayed {
                Color.clear
                    .contentShape(.rect)
                    .onTapGesture {
                        isMoreMenuDisplayed = false
                    }
            }
        }
        .animation(.easeInOut(duration: 0.3), value: isMoreMenuDisplayed)
        .onAppear {
            onAppear()
        }
    }

    var reactionImage: Image {
        switch comment.reaction {
        case .like:
            Image.Icon.heartFilled
        case .dislike, .removeReaction:
            Image.Icon.heart
        }
    }

    var reactionColor: Color {
        switch comment.reaction {
        case .like:
            Color.SemanticV1.likePink
        case .dislike, .removeReaction:
            Color.SemanticV1.textSecondary
        }
    }

    @ViewBuilder
    var avatarImage: some View {
        RemoteImage(url: comment.userAvatarUrl, fallbackId: "1")
            .frame(width: 32, height: 32)
            .clipShape(Circle())
            .padding(.top, 6.0)
    }

    @ViewBuilder
    var mainContentAndTitles: some View {
        VStack {
            let topLineLineHeight: CGFloat = 16.0
            HStack(spacing: 3.0) {
                Button {
                    tapAuthor()
                } label: {
                    HStack(spacing: 3.0) {
                        Text(comment.userDisplayName)
                            .typographyV1(.caption3.lineHeight(topLineLineHeight))
                            .foregroundColor(.SemanticV1.textBrand)
                            .lineLimit(1)

                        if isCommentByClipAuthor {
                            Text(L10n.FeatureComments.creatorLabel)
                                .typographyV1(.caption3.lineHeight(topLineLineHeight))
                                .foregroundColor(.SemanticV1.textBrand)
                                .lineLimit(1)
                                .padding(.leading, 4.0)
                                .padding(.trailing, 3.0)
                                .padding(.vertical, 3.0)
                                .background {
                                    RoundedRectangle(cornerRadius: 4.0)
                                        .fill(Color.SemanticV1.fieldBackground)
                                }
                        }

                        Text(comment.createdAt.timeAgoDisplay())
                            .typographyV1(.caption3.lineHeight(topLineLineHeight))
                            .foregroundColor(.SemanticV1.textTertiary)
                            .lineLimit(1)
                    }
                }

                if showingTrackTimestamp {
                    Button {
                        tapTrackTimestamp(comment.trackTimestamp)
                    } label: {
                        Text(L10n.FeatureComments.at + " \(comment.trackTimestamp.format_m_ss)")
                            .typographyV1(.caption3.lineHeight(topLineLineHeight))
                            .foregroundColor(.SemanticV2.accentBrand)
                            .lineLimit(1)
                    }
                    .buttonStyle(.plain)
                }

                Spacer()
            }

            HStack {
                if isLongComment {
                    commentContent(isLimited: !hasExpandedLongComment)
                        .contentShape(.rect)
                        .onTapGesture {
                            tapExpandOnLongComment()
                        }
                } else {
                    commentContent(isLimited: false)
                }
                Spacer()
            }

            HStack {
                if comment.isReply {
                    loadMoreRepliesButton
                } else {
                    Button {
                        tapReplyAction()
                    } label: {
                        Text(L10n.FeatureComments.reply)
                            .typographyV1(.caption5)
                            .multilineTextAlignment(.leading)
                            .foregroundColor(.SemanticV1.textTertiary)
                            .lineLimit(1)
                    }
                    .buttonStyle(.plain)
                }
                Spacer()
            }
        }
    }
}

private extension CommentThreadItem {
    enum Constants {
        static let shortContentLength: Int = 128
    }

    var isLongComment: Bool {
        return comment.content.count >= Constants.shortContentLength
    }

    @ViewBuilder
    func commentContent(isLimited: Bool) -> some View {
        let prefixVersion = String(comment.content.prefix(Constants.shortContentLength) + "...")
        let commentText = isLimited ? prefixVersion : comment.content
        let formattedText = InteractiveTextFormatter.formatCommentText(commentText, mentions: comment.userMentions)

        VStack(alignment: .leading, spacing: .zero) {
            Text(formattedText)
                .typographyV1(.caption2)
                .multilineTextAlignment(.leading)
                .onInteractiveTextTapped(
                    userMention: { mention in
                        tapMentionedUser(mention)
                    },
                    trackTimestamp: { seconds in
                        tapTrackTimestamp(seconds)
                    }
                )

            if isLimited {
                Text(L10n.FeatureComments.readMore)
                    .typographyV1(.caption3)
                    .foregroundColor(.SemanticV1.textLink)
                    .padding(.bottom, 8.0)
            }
        }
    }
}

private extension CommentThreadItem {
    @ViewBuilder
    var loadMoreRepliesButton: some View {
        if isLastReply && hasMoreReplies {
            Button {
                tapLoadMoreReplies()
            } label: {
                let lc = L10n.FeatureComments.self
                HStack {
                    let readXRepliesText = parentReplyCount == 1 ? lc.readOneReply : lc.readXReplies(parentReplyCount)
                    Text(isFirstReply ? readXRepliesText : lc.loadMoreReplies)
                        .typographyV1(.caption5)
                        .multilineTextAlignment(.leading)
                        .foregroundColor(.SemanticV1.textTertiary)
                        .lineLimit(1)
                    Image(systemName: "chevron.down")
                        .font(.system(size: 12, weight: .medium))
                        .foregroundColor(.SemanticV1.textTertiary)
                }
            }
            .buttonStyle(.plain)
        } else {
            /* Bit of a hack. It messes up the spacing without this */
            Text(" ")
                .typographyV1(.caption5)
        }
    }

    @ViewBuilder
    var rightSideButtons: some View {
        VStack {
            let buttonSize: CGFloat = 24.0

            HStack(alignment: .top) {
                VStack(spacing: .zero) {
                    Button {
                        UIImpactFeedbackGenerator(style: .light).impactOccurred()
                        tapReaction()
                    } label: {
                        reactionImage
                            .resizable()
                            .frame(width: buttonSize, height: buttonSize)
                            .foregroundStyle(reactionColor)
                    }
                    .buttonStyle(.plain)

                    if comment.numLikes <= .zero {
                        EmptyView()
                    } else {
                        Text("\(comment.numLikes)")
                            .typographyV1(.monospaceSmall.lineHeight(12.0))
                            .foregroundStyle(Color.SemanticV1.textTertiary)
                    }
                }

                Menu(
                    content: {
                        Button {
                            tapReplyAction()
                        } label: {
                            Label(
                                title: { Text(L10n.FeatureComments.reply) },
                                icon: { Image.Icon.reply }
                            )
                        }

                        if isCommentByCurrentUser || isClipByCurrentUser {
                            Button(role: .destructive) {
                                deleteAction()
                            } label: {
                                Label(
                                    title: { Text(L10n.FeatureComments.delete) },
                                    icon: { Image.Icon.trashV1 }
                                )
                            }
                        }

                        if !isCommentByCurrentUser {
                            Button(role: .destructive) {
                                showingReplyReasonSheet = true
                            } label: {
                                Label(
                                    title: { Text(L10n.FeatureComments.report) },
                                    icon: { Image.Icon.flag }
                                )
                            }
                        }
                    },
                    label: {
                        Image.Icon.moreHorizontal
                            .resizable()
                            .frame(width: buttonSize, height: buttonSize)
                            .foregroundStyle(Color.SemanticV1.textSecondary)
                    }
                )
            }
            .sheet(isPresented: $showingReplyReasonSheet, onDismiss: {}, content: {
                CommentReportSheet(tappedSubmit: {
                    reportAction($0)
                    showingReplyReasonSheet = false
                })
                .presentationDetents(UIScreen.isCompact ? [.large] : [.medium])
            })

            Spacer()
        }
    }
}

private extension CommentThreadItem {
    enum KabobMenuOption: Equatable, Hashable {
        case delete, reply, report
    }
}

extension CommentThreadItem {
    static func == (lhs: CommentThreadItem, rhs: CommentThreadItem) -> Bool {
        lhs.comment == rhs.comment &&
            lhs.isLoading == rhs.isLoading &&
            lhs.parentReplyCount == rhs.parentReplyCount &&
            lhs.hasMoreReplies == rhs.hasMoreReplies &&
            lhs.hasExpandedLongComment == rhs.hasExpandedLongComment
    }
}

#if DEBUG
    #Preview {
        CommentThreadItem(
            ClipComment.mock(),
            isCommentByCurrentUser: true,
            isClipByCurrentUser: false,
            isLoading: false,
            parentReplyCount: 0,
            isFirstReply: false,
            isLastReply: false,
            hasMoreReplies: false,
            tapAuthor: {},
            tapReaction: {},
            tapReplyAction: {},
            tapTrackTimestamp: { _ in },
            tapLoadMoreReplies: {},
            tapExpandOnLongComment: {},
            reportAction: { _ in },
            deleteAction: {},
            onAppear: {}
        )
    }
#endif
