import ComposableArchitecture
import Errors
import Localization
import SwiftUI
import Utilities

private extension BrandedAlertMultiButton {
    static func makeTemporaryStore(
        _ style: MultiButtonAlertStyle,
        _ primaryActionTapped: @escaping () -> Void,
        _ secondaryButtonTapped: @escaping () -> Void
    ) -> Store<State, Action> {
        Store(initialState: BrandedAlertMultiButton.State(style: style)) {
            Reduce<Self.State, Self.Action> { _, action in
                switch action {
                case .binding:
                    return .none

                case .delegate(.tappedPrimaryButton):
                    primaryActionTapped()
                    return .none

                case .delegate(.tappedSecondaryButton):
                    secondaryButtonTapped()
                    return .none
                }
            }
        }
    }
}

struct BrandedAlertMultiButtonModifier: ViewModifier {
    let store: StoreOf<BrandedAlertMultiButton>
    private let animationDelay: TimeInterval
    private let dismissAlert: () -> Void

    init(
        style: MultiButtonAlertStyle,
        animationDelay: TimeInterval?,
        primaryButtonTapped: @escaping () -> Void,
        secondaryButtonTapped: @escaping () -> Void,
        dismissAlert: @escaping () -> Void
    ) {
        self.animationDelay = animationDelay ?? BrandedAlertStyle.multiButtonAlert(style).animationDelay
        self.dismissAlert = dismissAlert
        self.store = BrandedAlertMultiButton.makeTemporaryStore(style, primaryButtonTapped, secondaryButtonTapped)
    }

    func body(content: Content) -> some View {
        content.modifier(
            BrandedAlertModifier(
                alertView: BrandedAlertMultiButtonView(store: store),
                animationDelay: animationDelay,
                dismissAlert: dismissAlert
            )
        )
    }
}

public extension View {
    @ViewBuilder
    func brandedAlert<T>(
        item: Binding<T?>,
        style: MultiButtonAlertStyle,
        animationDelay: TimeInterval? = nil,
        primaryButtonTapped: @escaping () -> Void,
        secondaryButtonTapped: @escaping () -> Void
    ) -> some View {
        if let _ = item.wrappedValue {
            modifier(BrandedAlertMultiButtonModifier(
                style: style,
                animationDelay: animationDelay,
                primaryButtonTapped: primaryButtonTapped,
                secondaryButtonTapped: secondaryButtonTapped,
                dismissAlert: { item.wrappedValue = nil }
            ))
        } else {
            self
        }
    }

    @ViewBuilder
    func brandedAlert(
        isPresented: Binding<Bool>,
        style: MultiButtonAlertStyle,
        animationDelay: TimeInterval? = nil,
        primaryButtonTapped: @escaping () -> Void,
        secondaryButtonTapped: @escaping () -> Void
    ) -> some View {
        if isPresented.wrappedValue == true {
            modifier(BrandedAlertMultiButtonModifier(
                style: style,
                animationDelay: animationDelay,
                primaryButtonTapped: primaryButtonTapped,
                secondaryButtonTapped: secondaryButtonTapped,
                dismissAlert: { isPresented.wrappedValue = false }
            ))
        } else {
            self
        }
    }

    @ViewBuilder
    func brandedAlert(
        error: Binding<AnyError?>,
        animationDelay: TimeInterval? = nil,
        primaryButton: (String, () -> Void),
        secondaryButton: (String, () -> Void)
    ) -> some View {
        if let wrappedError = error.wrappedValue, let presentableError = wrappedError.presentableError {
            let (primaryButtonLabel, primaryButtonAction) = primaryButton
            let (secondaryButtonLabel, secondaryButtonAction) = secondaryButton

            modifier(BrandedAlertMultiButtonModifier(
                style: .custom(
                    MultiButtonAlertStyle.TextCopy(
                        title: presentableError.localizedTitle,
                        description: presentableError.localizedMessage ?? "",
                        primaryButtonLabel: primaryButtonLabel,
                        secondaryButtonLabel: secondaryButtonLabel
                    )
                ),
                animationDelay: animationDelay,
                primaryButtonTapped: primaryButtonAction,
                secondaryButtonTapped: secondaryButtonAction,
                dismissAlert: { error.wrappedValue = nil }
            ))
        } else {
            self
        }
    }
}
