import APIClient
import ComponentLibrary
import ComposableArchitecture
import Errors
import EventBusClient
import FeatureBrandedAlert
import GenAPI
import Localization
import SwiftUI
import Utilities

@Reducer
public struct EditDisplayStylesReducer {
    public typealias State = EditDisplayStylesState

    @Reducer(state: .equatable)
    public enum Destination {
        case alert(AlertState<Alert>)

        public enum Alert {
            case discardChanges
        }
    }

    public enum Action: BindableAction {
        case destination(PresentationAction<Destination.Action>)
        case binding(BindingAction<State>)
        case saveTapped
        case clearError
        case updateDisplayTags(String)
        case `internal`(Internal)
        case dismissTapped

        public enum Internal {
            case dismiss
            case saveStyleSummaryResponse(Result<Void, Error>)
        }
    }

    @Dependency(\.apiClientV2) var api
    @Dependency(\.telemetryClient) var telemetry
    @Dependency(\.dismiss) var dismiss
    @Dependency(\.eventBus.sendClipEvent) private var sendClipEvent

    public init() {}

    public var body: some ReducerOf<Self> {
        BindingReducer()
        Reduce<State, Action> { state, action in
            switch action {
            case .binding:
                return .none

            case .clearError:
                state.error = nil
                return .none

            case .saveTapped:
                state.isSaving = true
                let styleSummary = state.displayStylesField.currentValue

                return .run { [remoteId = state.clip.id.remoteId,
                               currentStyleSummary = state.displayStylesField.currentValue,
                               displayTags = state.clip.displayTags] send in
                        if currentStyleSummary != displayTags {
                            await send(.internal(.saveStyleSummaryResponse(Result(catching: { try await api.setStyleSummary(remoteId, styleSummary) }))))
                            await send(.internal(.dismiss))
                        }
                }

            case .internal(.saveStyleSummaryResponse(.success)):
                let displayTags = state.displayStylesField.currentValue
                state.displayStylesField = State.FieldState(value: displayTags)
                state.clip.displayTags = state.displayStylesField.initialValue
                sendClipEvent(.updateClip(state.clip))
                return .none

            case .internal(.saveStyleSummaryResponse(.failure(let error))):
                state.error = AnyError(error)
                return .none

            case .dismissTapped:
                guard state.displayStylesField.currentValue == state.clip.displayTags else {
                    // User has unsaved changes, show alert
                    state.destination = .alert(.init(
                        title: { TextState(L10n.FeatureClipDetail.discardCoverTitle) },
                        actions: {
                            ButtonState(role: .destructive, action: .send(.discardChanges)) { TextState(L10n.FeatureClipDetail.discardCoverConfirm) }
                            ButtonState(role: .cancel) { TextState(L10n.FeatureClipDetail.discardCoverCancel) }
                        },
                        message: { TextState(L10n.FeatureClipDetail.discardCoverUnsavedMessage) }
                    ))
                    return .none
                }
                return .send(.internal(.dismiss))

            case .updateDisplayTags(let newDisplayTags):
                state.displayStylesField.update(newDisplayTags)
                return .none

            case .internal(.dismiss):
                return .run { _ in await self.dismiss() }

            case .destination(.presented(.alert(.discardChanges))):
                state.destination = nil
                state.displayStylesField.reset()
                return .send(.internal(.dismiss))

            case .destination:
                return .none
            }
        }
    }
}
