import ComponentLibrary
import ComposableArchitecture
import SunoModelClient
import SwiftUI
import Utilities

@Reducer
public struct BrandedAlert {
    /**
        Adding here instead of using create enum
        so we can decouple create version from this trigger
     */
    public enum ForceCreateFlag {
        case none
        case forceText
    }

    @Reducer(state: .equatable)
    public enum Destination {
        case singleButtonAlert(BrandedAlertSingleButton)
        case multiButtonAlert(BrandedAlertMultiButton)
        case announceAlert(BrandedAlertAnnounce)
        case listAlert(BrandedAlertList)
        case featuredArtist(BrandedAlertFeaturedArtist)
        case versioningAlert(VersioningAlertSingleButton)
        case discountAlert(DiscountAlertSingleButton)
        case walkthroughAlert(BrandedAlertWalkthrough)
        case hookStatusAlert(BrandedAlertHookStatus)
    }

    @ObservableState
    public struct State: Equatable {
        public var alertStyle: BrandedAlertStyle
        @Presents public var destination: Destination.State?

        @ObservationStateIgnored @ObservedBox var singleButtonAlert: BrandedAlertSingleButton.State?
        @ObservationStateIgnored @ObservedBox var multiButtonAlert: BrandedAlertMultiButton.State?
        @ObservationStateIgnored @ObservedBox var announceAlert: BrandedAlertAnnounce.State?
        @ObservationStateIgnored @ObservedBox var listAlert: BrandedAlertList.State?
        @ObservationStateIgnored @ObservedBox var featuredArtist: BrandedAlertFeaturedArtist.State?
        @ObservationStateIgnored @ObservedBox var versioningAlert: VersioningAlertSingleButton.State?
        @ObservationStateIgnored @ObservedBox var discountAlert: DiscountAlertSingleButton.State?
        @ObservationStateIgnored @ObservedBox var walkthroughAlert: BrandedAlertWalkthrough.State?
        @ObservationStateIgnored @ObservedBox var hookStatusAlert: BrandedAlertHookStatus.State?

        public init(style: BrandedAlertStyle = .noAlert) {
            self.alertStyle = style

            switch style {
            case .noAlert:
                destination = nil
            case .announceAlert(let style):
                destination = .announceAlert(.init(style: style))
            case .singleButtonAlert(let style):
                destination = .singleButtonAlert(.init(style: style))
            case .multiButtonAlert(let style):
                destination = .multiButtonAlert(.init(style: style))
            case .listAlert(let style):
                destination = .listAlert(.init(style: style))
            case .featuredArtist(let style):
                destination = .featuredArtist(.init(style: style))
            case .versioningAlert(let style):
                destination = .versioningAlert(.init(style: style))
            case .discountAlert(let style):
                destination = .discountAlert(.init(style: style))
            case .walkthroughAlert(let style):
                destination = .walkthroughAlert(.init(style: style))
            case .hookStatusAlert(let style):
                destination = .hookStatusAlert(.init(style: style))
            }
        }
    }

    public enum Action: BindableAction {
        public enum Delegate {
            case didTriggerCreate(_ flag: ForceCreateFlag)
            case didTriggerInvitePromoCodeSheet
            case didTriggerWithIntentionToUpgrade
            case didTriggerWithIntentionToRemasterSong
            case didTriggerWithIntentionToAddVideoSongArt
        }

        case binding(BindingAction<State>)
        case destination(PresentationAction<Destination.Action>)
        case singleButtonAlert(BrandedAlertSingleButton.Action)
        case multiButtonAlert(BrandedAlertMultiButton.Action)
        case announceAlert(BrandedAlertAnnounce.Action)
        case listAlert(BrandedAlertList.Action)
        case featuredArtist(BrandedAlertFeaturedArtist.Action)
        case versioningAlert(VersioningAlertSingleButton.Action)
        case discountAlert(DiscountAlertSingleButton.Action)
        case hookStatusAlert(BrandedAlertHookStatus.Action)
        case setStyle(BrandedAlertStyle)
        case delegate(Delegate)
        case dismissAlert(BrandedAlertStyle)
    }

    @Dependency(SunoModelClient.self) var sunoModelClient

    public init() {}

    public var body: some ReducerOf<Self> {
        BindingReducer()

        Reduce<State, Action> { state, action in
            switch action {
            case .setStyle(let style):
                switch style {
                case .singleButtonAlert(let style):
                    state.destination = .singleButtonAlert(.init(style: style))
                case .multiButtonAlert(let style):
                    state.destination = .multiButtonAlert(.init(style: style))
                case .announceAlert(let style):
                    state.destination = .announceAlert(.init(style: style))
                case .listAlert(let style):
                    state.destination = .listAlert(.init(style: style))
                case .featuredArtist(let style):
                    state.destination = .featuredArtist(.init(style: style))
                case .versioningAlert(let style):
                    state.destination = .versioningAlert(.init(style: style))
                case .noAlert:
                    return .send(.dismissAlert(state.alertStyle))
                case .discountAlert(let style):
                    state.destination = .discountAlert(.init(style: style))
                case .walkthroughAlert(let style):
                    state.destination = .walkthroughAlert(.init(style: style))
                case .hookStatusAlert(let style):
                    state.destination = .hookStatusAlert(.init(style: style))
                }
                return .none

            case .dismissAlert:
                state.destination = nil
                state.alertStyle = .noAlert
                return .none

            case .destination(.presented(.announceAlert(.delegate(.exitButton)))),
                 .destination(.presented(.singleButtonAlert(.delegate(.tappedButton)))),
                 .destination(.presented(.singleButtonAlert(.delegate(.exitButton)))),
                 .destination(.presented(.multiButtonAlert(.delegate(.tappedPrimaryButton)))),
                 .destination(.presented(.multiButtonAlert(.delegate(.tappedSecondaryButton)))),
                 .destination(.presented(.listAlert(.delegate(.tappedButton)))),
                 .destination(.presented(.featuredArtist(.delegate(.exitButton)))),
                 .destination(.presented(.featuredArtist(.delegate(.tappedButton)))),
                 .destination(.presented(.versioningAlert(.delegate(.exitButton)))),
                 .destination(.presented(.discountAlert(.delegate(.exitButton)))),
                 .destination(.presented(.walkthroughAlert(.delegate(.exitButton)))),
                 .destination(.presented(.hookStatusAlert(.delegate(.tappedButton)))):
                return .send(.dismissAlert(state.alertStyle))

            case .destination(.presented(.announceAlert(.delegate(.exitToCreate)))):
                return .send(.delegate(.didTriggerCreate(.none)))

            case .destination(.presented(.versioningAlert(.delegate(.goToCreate)))):
                return .run(operation: { send in
                    await sunoModelClient.clearModelOverride()
                    await send(.delegate(.didTriggerCreate(.forceText)))
                })

            case .destination(.presented(.versioningAlert(.delegate(.bringUpSubscribe)))),
                 .destination(.presented(.discountAlert(.delegate(.bringUpSubscribe)))):
                return .send(.delegate(.didTriggerWithIntentionToUpgrade))

            case .destination(.presented(.versioningAlert(.delegate(.goToLibraryForRemaster)))):
                return .send(.delegate(.didTriggerWithIntentionToRemasterSong))

            case .destination(.presented(.walkthroughAlert(.delegate(.goToLibraryForVideoSongArt)))):
                return .send(.delegate(.didTriggerWithIntentionToAddVideoSongArt))

            case .destination,
                 .binding,
                 .delegate,
                 .announceAlert,
                 .singleButtonAlert,
                 .multiButtonAlert,
                 .listAlert,
                 .featuredArtist,
                 .versioningAlert,
                 .discountAlert,
                 .hookStatusAlert:
                /* Catch All */
                return .none
            }
        }
        .ifLet(\.$destination, action: \.destination)
        .ifLet(\.announceAlert, action: \.announceAlert) {
            BrandedAlertAnnounce()
        }
        .ifLet(\.singleButtonAlert, action: \.singleButtonAlert) {
            BrandedAlertSingleButton()
        }
        .ifLet(\.multiButtonAlert, action: \.multiButtonAlert) {
            BrandedAlertMultiButton()
        }
        .ifLet(\.listAlert, action: \.listAlert) {
            BrandedAlertList()
        }
        .ifLet(\.featuredArtist, action: \.featuredArtist) {
            BrandedAlertFeaturedArtist()
        }
        .ifLet(\.versioningAlert, action: \.versioningAlert) {
            VersioningAlertSingleButton()
        }
        .ifLet(\.discountAlert, action: \.discountAlert) {
            DiscountAlertSingleButton()
        }
        Analytics()
    }
}

#if DEBUG
    import Localization

    #Preview("you've been banned") {
        BrandedAlertView(
            Store(
                initialState: BrandedAlert.State(style: .singleButtonAlert(.custom(SingleButtonAlertStyle.TextCopy(
                    title: L10n.FeatureComments.jailTitle,
                    description: L10n.FeatureComments.jailDescription,
                    buttonLabel: L10n.FeatureComments.jailButtonTitle
                )
                ))),
                reducer: { BrandedAlert() }
            )
        )
    }
#endif
