import ComponentLibrary
import ComposableArchitecture
import Localization
import SwiftUI

// swiftlint:disable file_length

@Reducer
public struct VersioningAlertSingleButton {
    @ObservableState
    public struct State: Equatable {
        var style: VersioningAlertStyle
    }

    public enum Action: BindableAction {
        case delegate(Delegate)
        case binding(BindingAction<State>)

        public enum Delegate {
            case goToCreate
            case bringUpSubscribe
            case exitButton
            case goToLibraryForRemaster
        }
    }

    public init() {}

    public var body: some ReducerOf<Self> {
        BindingReducer()
        Reduce<State, Action> { _, action in
            switch action {
            case .delegate,
                 .binding:
                /* Catch-all */
                return .none
            }
        }
    }
}

struct VersioningAlertSingleButtonView: View {
    @Bindable var store: StoreOf<VersioningAlertSingleButton>
    @State private var isMotionTriggeredProxy: Bool = false

    public init(store: StoreOf<VersioningAlertSingleButton>) {
        self.store = store
    }

    var body: some View {
        ZStack {
            Color.clear
                .background {
                    VersioningV4Background(style: store.style.auraColor)
                    Color.clear
                        .background(
                            LinearGradient(
                                stops: [
                                    Gradient.Stop(color: Color.SemanticV1.backgroundBlockOverlay.opacity(0), location: 0.00),
                                    Gradient.Stop(color: Color.SemanticV1.backgroundBlockOverlay.opacity(0.8), location: 1.00),
                                ],
                                startPoint: UnitPoint(x: 0.5, y: 0),
                                endPoint: UnitPoint(x: 0.5, y: 1.0)
                            )
                        )
                }
            copyStack

            Group {
                exitButtonStack
                ctaButton
            }
            .environment(\.colorScheme, .light)
        }
        .frame(width: 313.0, height: alertHeight)
        .clipShape(.rect(cornerRadius: 24.0))
        .onTapGesture {
            switch tapAction {
            case .dismissOnly:
                store.send(.delegate(.exitButton))
            case .goToCreate:
                store.send(.delegate(.goToCreate))
            case .openSubscriptionPage:
                store.send(.delegate(.bringUpSubscribe))
            case .goToLibraryForRemaster:
                store.send(.delegate(.goToLibraryForRemaster))
            }
        }
    }

    var alertHeight: CGFloat {
        switch store.style {
        case .preset(.v4FreeUserAnnounce),
             .preset(.v4PaidUserAnnounce),
             .preset(.v4PaidUserAnnounceV2),
             .preset(.v4InformationWithDismissV2),
             .preset(.v4InformationWithCreateRedirectV2):
            return 410.0
        case .preset(.v4FreeUserAnnounceV2),
             .preset(.v4RemasterAnnounce):
            return 390.0
        case .preset(.v4FreeUserHitYourLimit),
             .preset(.v4FreeUserCountRemainingContinue):
            return 330.0
        case .preset(.v4InformationWithCreateRedirect),
             .preset(.v4InformationWithDismiss),
             .preset(.v4UpgradeToV4),
             .preset(.v4FreeUserUpgradeInfoPush),
             .preset(.v4_5FreeUserUpgradeInfoPush):
            return 317.0
        }
    }
}

private extension VersioningAlertSingleButtonView {
    enum Constants {
        static let exitCircleSize: CGFloat = 40.0
        static let exitButtonPadding: CGFloat = 12.0
    }

    var copyData: VersioningAlertStyle.TextCopy {
        return store.style.textCopy
    }

    var tapAction: VersioningAlertStyle.TapAction {
        return store.style.tapAction
    }

    var countRemaining: Int {
        return store.style.textCopy.countLeft
    }

    @ViewBuilder
    var copyStack: some View {
        ZStack {
            switch store.style {
            case .preset(.v4PaidUserAnnounce),
                 .preset(.v4PaidUserAnnounceV2),
                 .preset(.v4InformationWithDismissV2),
                 .preset(.v4InformationWithCreateRedirectV2):
                v4IsHereAssetAndSummary
            case .preset(.v4FreeUserAnnounce):
                v4IsHereAssetMiddleAndSummary
            case .preset(.v4InformationWithCreateRedirect), .preset(.v4InformationWithDismiss):
                v4LogoAssetMiddleAndSummaryAltPadding
            case .preset(.v4UpgradeToV4):
                v4LogoAssetMiddleAndSummary
            case .preset(.v4FreeUserAnnounceV2):
                createWithV4AssetAndSummary
            case .preset(.v4FreeUserUpgradeInfoPush):
                v4AssetAndSummary
            case .preset(.v4FreeUserCountRemainingContinue):
                v4CountLeft
            case .preset(.v4FreeUserHitYourLimit):
                hitYourLimitAndSummary
            case .preset(.v4RemasterAnnounce):
                v4RemakeYourSongsAssetAndSummary
            case .preset(.v4_5FreeUserUpgradeInfoPush):
                v4_5AssetAndSummary
            }
        }
    }

    @ViewBuilder
    var v4IsHereAssetAndSummary: some View {
        VStack {
            Image.Assets.v4IsHere
                .resizable()
                .scaledToFit()
                .frame(width: 180.0)
                .padding(.bottom, 32.0)

            Text(copyData.mainSummaryCopy)
                .typographyV1(.caption)
                .padding(.horizontal, 32.0)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
        }
    }

    @ViewBuilder
    var v4IsHereAssetMiddleAndSummary: some View {
        VStack(spacing: .zero) {
            Image.Assets.v4IsHere
                .resizable()
                .scaledToFit()
                .frame(width: 180.0)
                .padding(.bottom, 24.0)

            Text(copyData.middleTitle)
                .typographyV1(.headline1.size { _ in 20.0 })
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
                .padding(.bottom, 16.0)

            Text(copyData.mainSummaryCopy)
                .typographyV1(.caption)
                .padding(.horizontal, 32.0)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
                .padding(.bottom, 8.0)
        }
        .padding(.bottom, 16.0)
    }

    @ViewBuilder
    var v4LogoAssetMiddleAndSummary: some View {
        VStack(spacing: .zero) {
            Image.Assets.v4Logo
                .resizable()
                .scaledToFit()
                .frame(width: 80.0)
                .padding(.bottom, 24.0)

            Text(copyData.middleTitle)
                .typographyV1(.headline1.size { _ in 20.0 })
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
                .padding(.bottom, 16.0)

            Text(copyData.mainSummaryCopy)
                .typographyV1(.body1)
                .padding(.horizontal, 44.0)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
                .padding(.bottom, 8.0)
        }
        .padding(.bottom, 16.0)
    }

    @ViewBuilder
    var createWithV4AssetAndSummary: some View {
        VStack {
            Image.Assets.v4CreateWith
                .resizable()
                .scaledToFit()
                .frame(width: 240.0, height: 123.0)
                .padding(.bottom, 16.0)
                .overlay {
                    HStack {
                        Spacer()
                            .frame(width: 175.0)

                        VStack {
                            Spacer()
                                .frame(height: 58.0)

                            Color.clear
                                .frame(width: 80.0, height: 64.0)
                                .background {
                                    let displacementSize: CGFloat = 72.0
                                    ZStack {
                                        Image.Assets.v4Logo
                                            .resizable()
                                            .scaledToFit()
                                            .frame(width: 62.0)
                                            .offset(
                                                x: .zero,
                                                y: isMotionTriggeredProxy ? .zero : displacementSize
                                            )

                                        Image.Assets.v3Dot5Large
                                            .resizable()
                                            .scaledToFit()
                                            .frame(width: 72.0)
                                            .offset(
                                                x: -4.0,
                                                y: isMotionTriggeredProxy ? -(displacementSize + 2.0) : -2.0
                                            )
                                    }
                                    .animation(
                                        .spring(
                                            duration: 0.9,
                                            bounce: 0.3
                                        )
                                        .delay(0.75),
                                        value: isMotionTriggeredProxy
                                    )
                                }
                                .clipped()
                                .onAppear {
                                    isMotionTriggeredProxy = true
                                }
                        }
                    }
                }

            Text(copyData.mainSummaryCopy)
                .typographyV1(.caption)
                .padding(.horizontal, 20.0)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
        }
    }

    @ViewBuilder
    var v4RemakeYourSongsAssetAndSummary: some View {
        VStack {
            Image.Assets.v4RemakeYourSongs
                .resizable()
                .scaledToFit()
                .frame(width: 240.0)
                .padding(.bottom, 16.0)

            Text(copyData.mainSummaryCopy)
                .typographyV1(.caption)
                .padding(.horizontal, 20.0)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
        }
    }

    @ViewBuilder
    var hitYourLimitAndSummary: some View {
        VStack {
            Image.Assets.v4HitYourLimit
                .resizable()
                .scaledToFit()
                .frame(width: 200.0)
                .padding(.bottom, 16.0)

            Text(copyData.mainSummaryCopy)
                .typographyV1(.caption)
                .padding(.horizontal, 32.0)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
                .padding(.bottom, 32.0)
        }
    }

    @ViewBuilder
    var v4CountLeft: some View {
        VStack(spacing: .zero) {
            /* This is messy but accurate */
            let count = countRemaining
            let fontSize: CGFloat = 44.0

            HStack {
                Text("\(count) \(L10n.FeatureBrandedAlert.v4FreeWord.uppercased())")
                    .typographyV1(.headline2.size { _ in fontSize })
                    .foregroundStyle(Color.SemanticV1.v4Accent)
                    .offset(x: .zero, y: 2)

                Image.Assets.v4Logo
                    .resizable()
                    .scaledToFit()
                    .frame(width: fontSize)
                    .offset(y: -1.0)
            }

            HStack {
                Text(L10n.FeatureBrandedAlert.v4SongsLeftNoNumber(count).uppercased())
                    .typographyV1(.headline2.size { _ in fontSize })
                    .foregroundStyle(Color.SemanticV1.v4Accent)
            }
            .padding(.bottom, 16.0)

            Text(L10n.FeatureBrandedAlert.v4ToGiveYouATaste)
                .typographyV1(.caption)
                .padding(.horizontal, 32.0)
                .multilineTextAlignment(.center)
                .lineLimit(3)
                .foregroundStyle(Color.SemanticV1.v4Accent)
                .padding(.bottom, 16.0)
        }
    }

    @ViewBuilder
    var v4AssetAndSummary: some View {
        VStack {
            Text(L10n.FeatureBrandedAlert.v4Model)
                .typographyV1(.displaySmall)
                .padding(.horizontal, 20)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV2.foregroundPrimaryOnDark)
                .padding(.bottom, 4)

            Text(copyData.mainSummaryCopy)
                .typographyV1(.subtitleSmallNew)
                .padding(.horizontal, 38)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV2.foregroundPrimaryOnDark)
                .padding(.bottom, 32)
        }
    }

    @ViewBuilder
    var v4LogoAssetMiddleAndSummaryAltPadding: some View {
        VStack(spacing: .zero) {
            Image.Assets.v4Logo
                .resizable()
                .scaledToFit()
                .frame(height: 60.0)
                .padding(.bottom, 24.0)

            Text(copyData.middleTitle)
                .typographyV1(.headline1.size { _ in 20.0 })
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
                .padding(.bottom, 16.0)

            Text(copyData.mainSummaryCopy)
                .typographyV1(.caption)
                .padding(.horizontal, 32.0)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV1.v4Accent)
                .padding(.bottom, 8.0)
        }
        .padding(.bottom, 32.0)
    }

    @ViewBuilder
    var v4_5AssetAndSummary: some View {
        VStack {
            Text(L10n.FeatureBrandedAlert.newModelEmphasize)
                .typographyV1(.subtitleXsmall)
                .foregroundStyle(Color.SemanticV1.textOnLight) // V2 doesn't have prominent `onLight` colors yet
                .padding(.horizontal, 6)
                .padding(.vertical, 2)
                .background {
                    RoundedRectangle(cornerRadius: 15)
                        .fill(Color.SemanticV2.accentBrand)
                }
                .padding(.bottom, 20)

            Text(L10n.FeatureBrandedAlert.v4point5JustDropped)
                .typographyV1(.displaySmall)
                .padding(.horizontal, 20)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV2.foregroundPrimaryOnDark)
                .padding(.bottom, 4)

            Text(copyData.mainSummaryCopy)
                .typographyV1(.subtitleSmallNew)
                .padding(.horizontal, 38)
                .multilineTextAlignment(.center)
                .foregroundStyle(Color.SemanticV2.foregroundPrimaryOnDark)
                .padding(.bottom, 32)
        }
        .shadow(color: .black.opacity(0.2), radius: 3, x: 2, y: 2)
        .shadow(color: .black.opacity(0.1), radius: 8, x: 6, y: 6)
    }

    @ViewBuilder
    var ctaButton: some View {
        VStack {
            Spacer()
            Button {
                switch tapAction {
                case .dismissOnly:
                    store.send(.delegate(.exitButton))
                case .goToCreate:
                    store.send(.delegate(.goToCreate))
                case .openSubscriptionPage:
                    store.send(.delegate(.bringUpSubscribe))
                case .goToLibraryForRemaster:
                    store.send(.delegate(.goToLibraryForRemaster))
                }

            } label: {
                ZStack {
                    Color.SemanticV1.backgroundPrimary
                    Text(copyData.buttonCopy)
                        .typographyV1(.button1)
                        .foregroundStyle(Color.SemanticV1.textPrimary)
                }
            }
            .contentShape(.rect)
            .frame(height: 56.0)
            .background {
                Color.clear
            }
            .padding(.top, 1.0)
            .background {
                Color.black.opacity(0.15)
            }
        }
    }

    @ViewBuilder
    var tinyStar: some View {
        Image.Assets.v4StarDot
            .resizable()
            .scaledToFit()
            .frame(width: 8.0)
    }

    @ViewBuilder
    var exitButtonStack: some View {
        VStack {
            HStack {
                Spacer()
                Button {
                    store.send(.delegate(.exitButton))
                } label: {
                    ZStack {
                        Circle()
                            .fill(Color.SemanticV1.backgroundPrimary)
                            .frame(width: Constants.exitCircleSize, height: Constants.exitCircleSize)
                        Image.Icon.close
                            .foregroundStyle(Color.SemanticV1.textPrimary)
                    }
                    .padding(.top, Constants.exitButtonPadding)
                    .padding(.trailing, Constants.exitButtonPadding)
                }
            }
            Spacer()
        }
    }
}
