import ComposableArchitecture
import SwiftUI

public struct PreviewableClipCard: View {
    let title: String
    let tags: String
    let imageUrl: String
    let videoCoverUrl: String?
    let videoCoverPreviewUrl: String?
    let playCount: Int
    let upvoteCount: Int
    let isLiked: Bool
    let commentCount: Int
    let avatarImageUrl: String?
    let displayName: String
    let userId: String?
    let clipId: String?
    let isLoading: Bool
    let didFailToLoad: Bool
    let isVideoCoverPlaying: Bool
    let cardTappedAction: () -> Void
    let authorTappedAction: () -> Void

    @Dependency(VideoCoverClient.self) var videoCoverClient

    var isPlayingCover: Bool {
        guard let videoCoverUrl, let videoCoverPreviewUrl else { return false }
        return isVideoCoverPlaying && (videoCoverClient.currentPreviewItemUrl() == videoCoverPreviewUrl)
    }

    public init(
        title: String,
        tags: String,
        imageUrl: String,
        videoCoverUrl: String?,
        videoCoverPreviewUrl: String?,
        playCount: Int,
        upvoteCount: Int,
        isLiked: Bool,
        commentCount: Int,
        avatarImageUrl: String?,
        displayName: String,
        userId: String?,
        clipId: String?,
        isLoading: Bool,
        didFailToLoad: Bool = false,
        isVideoCoverPlaying: Bool,
        cardTappedAction: @escaping () -> Void,
        authorTappedAction: @escaping () -> Void
    ) {
        if isLoading {
            self.title = ""
            self.tags = ""
            self.imageUrl = ""
            self.videoCoverUrl = nil
            self.videoCoverPreviewUrl = nil
            self.playCount = 0
            self.upvoteCount = 0
            self.isLiked = false
            self.commentCount = 0
            self.avatarImageUrl = nil
            self.displayName = ""
            self.userId = nil
            self.clipId = nil
            self.isVideoCoverPlaying = false
        } else {
            self.title = title
            self.tags = tags
            self.imageUrl = imageUrl
            self.videoCoverUrl = videoCoverUrl
            self.videoCoverPreviewUrl = videoCoverPreviewUrl
            self.playCount = playCount
            self.upvoteCount = upvoteCount
            self.isLiked = isLiked
            self.commentCount = commentCount
            self.avatarImageUrl = avatarImageUrl
            self.displayName = displayName
            self.userId = userId
            self.clipId = clipId
            self.isVideoCoverPlaying = isVideoCoverPlaying
        }
        self.isLoading = isLoading
        self.didFailToLoad = didFailToLoad
        self.cardTappedAction = cardTappedAction
        self.authorTappedAction = authorTappedAction
    }

    private var annotationSizingScalar: CGFloat {
        return 3.6
    }

    private var annotationHeight: CGFloat {
        return 50.0
    }

    public var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            clipInfoRowButton
            authorRowButton
        }
        .allowsHitTesting(!isLoading)
        .placeholderShimmering(isVisible: isShimmering)
    }

    private var clipInfoRowButton: some View {
        Button(action: cardTappedAction) {
            clipInfoRowLabel
        }
        .contentShape(.rect)
        .buttonStyle(ScaleButtonStyle(scaleAmount: 0.98))
    }

    private var clipInfoRowLabel: some View {
        VStack(spacing: 16) {
            songArt
            clipTitleAndTags
        }
    }

    private var isShimmering: Bool {
        isLoading && !didFailToLoad
    }

    @ViewBuilder
    private var songArt: some View {
        ZStack {
            clipImage
            if isPlayingCover {
                videoCover
            }
        }
        .overlay(alignment: .bottom) {
            GeometryReader { geoProxy in
                ZStack(alignment: .bottom) {
                    Color.clear
                    HStack(spacing: 8.0) {
                        playCountLabel(geoProxy.size.width)
                        upvoteCountLabel(geoProxy.size.width)
                        commentCountLabel(geoProxy.size.width)
                    }
                    .padding(.bottom, 8.0)
                }
                .environment(\.colorScheme, .dark)
                .opacity(isLoading ? 0 : 1)
            }
        }
        .frame(maxWidth: .infinity)
        .placeholder(isVisible: isLoading)
    }

    private var clipImage: some View {
        RemoteImage(url: imageUrl, fallbackId: clipId)
            .cornerRadius(12)
            .aspectRatio(3 / 4, contentMode: .fit)
    }

    @ViewBuilder
    private var videoCover: some View {
        VideoCoverView(
            player: videoCoverClient.getAVPlayer(),
            resizeMode: .resizeAspectFill,
            cornerRadius: 12
        )
        .cornerRadius(12)
        .aspectRatio(3 / 4, contentMode: .fit)
    }

    private func playCountLabel(_ parentWidth: CGFloat) -> some View {
        VStack(spacing: 4) {
            Image.Icon.playFilled
                .resizable()
                .frame(width: 16.0, height: 16.0)
                .foregroundColor(.SemanticV1.iconPrimary)
            Text(playCount.formatted(.number.notation(.compactName)))
                .typographyV1(.monospace.size { _ in 14.0 })
                .foregroundColor(.SemanticV1.textPrimary)
        }
        .frame(
            width: parentWidth / annotationSizingScalar,
            height: annotationHeight
        )
        .background(Material.ultraThin)
        .clipShape(.rect(cornerRadius: 8))
    }

    private func upvoteCountLabel(_ parentWidth: CGFloat) -> some View {
        VStack(spacing: 4) {
            Image.Icon.thumbsUpFilled15V1
                .resizable()
                .frame(width: 16.0, height: 16.0)
                .foregroundColor(.SemanticV1.iconPrimary)

            Text(upvoteCount.formatted(.number.notation(.compactName)))
                .typographyV1(.monospace.size { _ in 14.0 })
                .foregroundColor(.SemanticV1.textPrimary)
        }
        .frame(
            width: parentWidth / annotationSizingScalar,
            height: annotationHeight
        )
        .background(Material.ultraThin)
        .clipShape(.rect(cornerRadius: 8))
    }

    private func commentCountLabel(_ parentWidth: CGFloat) -> some View {
        VStack(spacing: 4) {
            Image.Icon.commentBubbleMore
                .resizable()
                .frame(width: 16.0, height: 16.0)
                .foregroundColor(.SemanticV1.iconPrimary)

            Text(commentCount.formatted(.number.notation(.compactName)))
                .typographyV1(.monospace.size { _ in 14.0 })
                .foregroundColor(.SemanticV1.textPrimary)
        }
        .frame(
            width: parentWidth / annotationSizingScalar,
            height: annotationHeight
        )
        .background(Material.ultraThin)
        .clipShape(.rect(cornerRadius: 8))
    }

    private var clipTitleAndTags: some View {
        VStack(alignment: .leading, spacing: isLoading ? 10 : 0) {
            Text(title)
                .typographyV1(.body3)
                .foregroundColor(.SemanticV1.textPrimary)
                .lineLimit(1)
                .frame(maxWidth: .infinity, alignment: .leading)
                .placeholder(isVisible: isLoading)

            Text(tags.isEmpty ? " " : tags.capitalized)
                .typographyV1(.body2)
                .foregroundColor(.SemanticV1.textBrand)
                .lineLimit(1, reservesSpace: true)
                .fixedSize(horizontal: false, vertical: true)
                .frame(maxWidth: .infinity, alignment: .leading)
                .placeholder(isVisible: isLoading)
        }
    }

    private var authorRowButton: some View {
        Button(action: authorTappedAction) {
            authorRowLabel
        }
        .placeholder(isVisible: isLoading)
        .buttonStyle(ScaleButtonStyle(scaleAmount: 0.98))
        .padding(.top, 8)
    }

    private var authorRowLabel: some View {
        HStack(spacing: 4) {
            RemoteImage(url: avatarImageUrl, fallbackId: userId)
                .frame(width: 24, height: 24)
                .clipShape(Circle())
            Text(displayName)
                .typographyV1(.caption2)
                .foregroundColor(.SemanticV1.textPrimary)
                .lineLimit(1)
        }
    }
}
