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

@Reducer
public struct EditDisplayedLyricsReducer {
    public typealias State = EditDisplayedLyricsState

    @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 updateLyrics(String)
        case clearError
        case `internal`(Internal)
        case dismissTapped

        public enum Internal {
            case dismiss
            case updateLyricsResponse(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
                return .run { [clip = state.clip, lyrics = state.lyricsField.currentValue] send in
                    let update = ClipMetadataSpec(lyrics: lyrics)
                    let result = await Result { try await api.updateClip(clip.id.remoteId, update) }
                    await send(.internal(.updateLyricsResponse(result)))
                }

            case .updateLyrics(let newLyrics):
                state.lyricsField.update(newLyrics)
                return .none

            case .dismissTapped:
                guard state.lyricsField.currentValue == state.clip.prompt 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 .internal(.updateLyricsResponse(.success)):
                let lyrics = state.lyricsField.currentValue
                state.lyricsField = EditDisplayedLyricsState.FieldState(value: lyrics)
                state.clip.prompt = lyrics
                state.toggleHapticSuccess.toggle()
                sendClipEvent(.updateClip(state.clip))
                return .send(.internal(.dismiss))

            case .internal(.updateLyricsResponse(.failure(let error))):
                state.isSaving = false
                state.error = AnyError(error)
                state.toggleHapticError.toggle()
                log.telemetry.error(error)
                return .none

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

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

            case .destination:
                return .none
            }
        }
    }
}
