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

struct CommentSheetItem: View, Equatable {
    let comment: CommentEntity
    let isCommentByCurrentUser: Bool
    let isEntityByCurrentUser: Bool
    let isCommentByEntityAuthor: 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 private var isMoreMenuDisplayed: Bool = false

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

    private let isLongComment: Bool
    private let showingTrackTimestamp: Bool
    private let showingOnSongLabel: Bool

    init(
        _ comment: CommentEntity,
        isCommentByCurrentUser: Bool,
        isEntityByCurrentUser: Bool,
        isCommentByEntityAuthor: Bool = false,
        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.isEntityByCurrentUser = isEntityByCurrentUser
        self.isCommentByEntityAuthor = isCommentByEntityAuthor
        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

        self.isLongComment = comment.content.count >= Constants.shortContentLength
        self.showingTrackTimestamp = !comment.isReply && comment.trackTimestamp >= 1
        self.showingOnSongLabel = !comment.isReply && comment.entityType == .clip
    }

    var body: some View {
        ZStack {
            HStack(alignment: .top) {
                Group {
                    avatarSection
                    mainContentSection
                }
                .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()
        }
    }
}

private extension CommentSheetItem {
    var avatarSection: some View {
        Button {
            tapAuthor()
        } label: {
            RemoteImage(url: comment.userAvatarUrl, fallbackId: "1")
                .frame(width: 32, height: 32)
                .clipShape(Circle())
                .padding(.top, 6.0)
        }
    }
}

// MARK: Main content section

private extension CommentSheetItem {
    static var topLineLineHeight: CGFloat = 16.0

    var mainContentSection: some View {
        VStack {
            topLineSection
            commentContentSection
            replyOrLoadMoreSection
        }
    }

    var topLineSection: some View {
        HStack(spacing: 3.0) {
            Button {
                tapAuthor()
            } label: {
                HStack(spacing: 3.0) {
                    Text(comment.userDisplayName)
                        .typographyV1(.caption3.lineHeight(CommentSheetItem.topLineLineHeight))
                        .foregroundColor(.SemanticV1.textBrand)
                        .lineLimit(1)

                    if isCommentByEntityAuthor {
                        creatorLabel
                    }
                }
            }

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

            if showingOnSongLabel {
                Text(L10n.FeatureComments.onSong)
                    .typographyV1(.caption3.lineHeight(CommentSheetItem.topLineLineHeight))
                    .foregroundColor(.SemanticV2.accentBrand)
                    .lineLimit(1)
            }

            Spacer()
        }
    }

    var creatorLabel: some View {
        Text(L10n.FeatureComments.creatorLabel)
            .typographyV1(.caption3.lineHeight(CommentSheetItem.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)
            }
    }

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

    var replyOrLoadMoreSection: some View {
        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()
        }
    }
}

// MARK: Comment content section

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

    @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,
            config: comment.entityType == .hook ? .hookComment : .comment
        )

        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)
            }
        }
    }
}

// MARK: Load more replies button

private extension CommentSheetItem {
    @ViewBuilder
    var loadMoreRepliesButton: some View {
        if isLastReply && hasMoreReplies {
            Button {
                tapLoadMoreReplies()
            } label: {
                let lc = L10n.FeatureComments.self
                let readXRepliesText = parentReplyCount == 1 ? lc.readOneReply : lc.readXReplies(parentReplyCount)
                HStack {
                    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)
        }
    }
}

// MARK: - Right side buttons

private extension CommentSheetItem {
    var rightSideButtons: some View {
        VStack {
            HStack(alignment: .top) {
                VStack(spacing: .zero) {
                    reactionButton
                    likeCountText
                }
                moreMenuButton
            }
            .sheet(isPresented: $showingReportReasonSheet, onDismiss: {}, content: {
                CommentReportSheet(tappedSubmit: {
                    reportAction($0)
                    showingReportReasonSheet = false
                })
                .presentationDetents(UIScreen.isCompact ? [.large] : [.medium])
            })

            Spacer()
        }
    }

    var reactionButton: some View {
        Button {
            UIImpactFeedbackGenerator(style: .light).impactOccurred()
            tapReaction()
        } label: {
            reactionImage
                .resizable()
                .frame(width: 24.0, height: 24.0)
                .foregroundStyle(reactionColor)
        }
        .buttonStyle(.plain)
    }

    @ViewBuilder
    var likeCountText: some View {
        if comment.numLikes <= .zero {
            EmptyView()
        } else {
            Text("\(comment.numLikes)")
                .typographyV1(.monospaceSmall.lineHeight(12.0))
                .foregroundStyle(Color.SemanticV1.textTertiary)
        }
    }

    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
        }
    }
}

// MARK: - More menu

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

    var moreMenuButton: some View {
        Menu {
            if !comment.isReply {
                moreMenuReplyButton
            }
            if isCommentByCurrentUser || isEntityByCurrentUser {
                moreMenuDeleteButton
            }
            if !isCommentByCurrentUser {
                moreMenuReportButton
            }
        } label: {
            Image.Icon.moreHorizontal
                .resizable()
                .frame(width: 24.0, height: 24.0)
                .foregroundStyle(Color.SemanticV1.textSecondary)
        }
    }

    var moreMenuReplyButton: some View {
        Button {
            tapReplyAction()
        } label: {
            Label(
                title: { Text(L10n.FeatureComments.reply) },
                icon: {
                    Image.Icon.reply
                        .renderingMode(.template)
                }
            )
        }
    }

    var moreMenuDeleteButton: some View {
        Button(role: .destructive) {
            deleteAction()
        } label: {
            Label(
                title: { Text(L10n.FeatureComments.delete) },
                icon: { Image.Icon.trashV1 }
            )
        }
    }

    var moreMenuReportButton: some View {
        Button(role: .destructive) {
            showingReportReasonSheet = true
        } label: {
            Label(
                title: { Text(L10n.FeatureComments.report) },
                icon: { Image.Icon.flag }
            )
        }
    }
}

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

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