import APIClient
import ComponentLibrary
import ComposableArchitecture
import FeatureHookSnippetSelection
import Foundation
import SwiftUI
import Utilities

public struct HooksSnippetPlayingModeActions {
    public let onPlayPauseTapped: () -> Void
    public let onProceedTapped: () -> Void

    public init(
        onPlayPauseTapped: @escaping () -> Void,
        onProceedTapped: @escaping () -> Void
    ) {
        self.onPlayPauseTapped = onPlayPauseTapped
        self.onProceedTapped = onProceedTapped
    }
}

public enum HooksSnippetPlayerMode: Equatable {
    case playing(HooksSnippetPlayingModeActions)

    public static func == (lhs: Self, rhs: Self) -> Bool {
        switch (lhs, rhs) {
        case (.playing, .playing):
            return true
        }
    }
}

public struct HooksSnippetPlayerView: View {
    let thumbnail: String
    let songTitle: String
    let songTags: String
    let displayTags: String?
    let isPlaying: Bool
    let mode: HooksSnippetPlayerMode
    let clipModel: Clip.HighLevelModelVersion

    private let tagFont: TypographyV1 = .tagText

    public init(
        thumbnail: String,
        songTitle: String,
        songTags: String,
        displayTags: String?,
        isPlaying: Bool,
        mode: HooksSnippetPlayerMode,
        clipModel: Clip.HighLevelModelVersion
    ) {
        self.thumbnail = thumbnail
        self.songTitle = songTitle
        self.songTags = songTags
        self.displayTags = displayTags
        self.isPlaying = isPlaying
        self.mode = mode
        self.clipModel = clipModel
    }

    public var body: some View {
        VStack {
            content
                .padding(.top, 26)
                .padding(.horizontal, 8)
                .padding(.bottom, 40)
        }
        .environment(\.colorScheme, .dark)
        .background(
            LinearGradient(
                colors: Color.Gradient.clearBlackLinearGradient,
                startPoint: .top,
                endPoint: .bottom
            )
        )
    }

    @ViewBuilder
    private var content: some View {
        switch mode {
        case .playing(let actions):
            playingContent(actions: actions)
                .transition(.asymmetric(
                    insertion: .opacity.combined(with: .move(edge: .bottom)),
                    removal: .opacity.combined(with: .move(edge: .bottom))
                ))
        }
    }

    @ViewBuilder
    private func playingContent(actions: HooksSnippetPlayingModeActions) -> some View {
        HStack(spacing: 10) {
            songThumbnail
            songTitleAndStyleTags
            Spacer()
            HStack(spacing: 20) {
                playPauseButton(onPlayPauseTapped: actions.onPlayPauseTapped)
                proceedButton(onProceedTapped: actions.onProceedTapped)
            }
        }
        .frame(height: 68)
        .padding(.horizontal, 12)
        .background(Color.SemanticV1.backgroundTertiary)
        .cornerRadius(46)
    }

    @ViewBuilder
    private var songThumbnail: some View {
        RemoteImage(url: thumbnail, fallbackId: songTitle)
            .frame(width: 44, height: 44)
            .clipShape(Circle())
    }

    @ViewBuilder
    private var scrollingTitle: some View {
        MarqueeText(
            text: songTitle,
            font: TypographyV1.titleText.uiFont ?? .systemFont(ofSize: 14),
            leftFade: 0.5,
            rightFade: 0.5,
            startDelay: 2,
            alignment: .leading
        )
        .foregroundColor(.SemanticV1.textPrimary)
    }

    @ViewBuilder
    private var styleTags: some View {
        if let displayTags = displayTags, !displayTags.isEmpty, clipModel == .v4_5 {
            MarqueeText(
                text: displayTags,
                font: TypographyV1.tagText.uiFont ?? .systemFont(ofSize: 12),
                leftFade: 0.5,
                rightFade: 0.5,
                startDelay: 2,
                alignment: .leading
            )
            .foregroundColor(.SemanticV1.textSecondary)
        } else if !songTags.isEmpty {
            TagText(songTags, fontSize: 12, font: .tagText, textColor: .SemanticV1.textSecondary)
        }
    }

    @ViewBuilder
    private var songTitleAndStyleTags: some View {
        VStack(alignment: .leading, spacing: 2) {
            scrollingTitle
            styleTags
        }
    }

    @ViewBuilder
    private func playPauseButton(onPlayPauseTapped: @escaping () -> Void) -> some View {
        Button {
            onPlayPauseTapped()
        } label: {
            if isPlaying {
                Image.Icon.pause
                    .renderingMode(.template)
                    .resizable()
                    .frame(width: 24, height: 24)
                    .foregroundColor(.SemanticV1.textPrimary)
            } else {
                Image.Icon.playFilled
                    .renderingMode(.template)
                    .resizable()
                    .frame(width: 24, height: 24)
                    .foregroundColor(.SemanticV1.textPrimary)
            }
        }
        .animation(.none, value: isPlaying)
        .buttonStyle(ScaleButtonStyle(scaleAmount: 0.9))
    }

    @ViewBuilder
    private func proceedButton(onProceedTapped: @escaping () -> Void) -> some View {
        Button {
            onProceedTapped()
        } label: {
            ZStack {
                Circle()
                    .fill(Color.SemanticV1.textPrimary)
                    .frame(width: 44, height: 44)

                Image.Icon.arrowRightV2
                    .renderingMode(.template)
                    .resizable()
                    .frame(width: 25.88, height: 25.88)
                    .foregroundColor(.SemanticV1.backgroundPrimary)
            }
        }
        .buttonStyle(ScaleButtonStyle(scaleAmount: 0.9))
    }
}

private extension TypographyV1 {
    static let tagText: TypographyV1 = .init(
        name: "Tag Text",
        size: 12,
        style: .body,
        weight: .ppNeueMontrealRegular,
        kerning: 0.24,
        lineHeight: 16
    )

    static let titleText: TypographyV1 = .init(
        name: "Title Text",
        size: 14,
        style: .body,
        weight: .ppNeueMontrealMedium,
        kerning: 0.28,
        lineHeight: 18
    )
}
