import ComposableArchitecture
import Errors
import Localization
import SwiftUI
import Utilities

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

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

                case .delegate(.exitButton):
                    exitButtonTapped()
                    return .none
                }
            }
        }
    }
}

struct BrandedAlertSingleButtonModifier: ViewModifier {
    let store: StoreOf<BrandedAlertSingleButton>
    private let animationDelay: TimeInterval

    init(
        style: SingleButtonAlertStyle,
        animationDelay: TimeInterval?,
        primaryButtonTapped: @escaping () -> Void,
        exitButtonTapped: @escaping () -> Void
    ) {
        self.store = BrandedAlertSingleButton.makeTemporaryStore(style, primaryButtonTapped, exitButtonTapped)
        self.animationDelay = animationDelay ?? BrandedAlertStyle.singleButtonAlert(style).animationDelay
    }

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

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

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

    @ViewBuilder
    func brandedAlert(error: Binding<AnyError?>, animationDelay: TimeInterval? = nil, _ primaryButtonTapped: @escaping () -> Void = {}) -> some View {
        if let wrappedError = error.wrappedValue, let presentableError = wrappedError.presentableError {
            modifier(BrandedAlertSingleButtonModifier(
                style: .custom(
                    SingleButtonAlertStyle.TextCopy(
                        title: presentableError.localizedTitle,
                        description: presentableError.localizedMessage ?? "",
                        buttonLabel: L10n.FeatureBrandedAlert.ok
                    )
                ),
                animationDelay: animationDelay,
                primaryButtonTapped: primaryButtonTapped,
                exitButtonTapped: { error.wrappedValue = nil }
            ))
        } else {
            self
        }
    }
}
