import Foundation
import ComposeApp

/// Utility for observing Kotlin StateFlow and handling ApiResult states.
/// This eliminates the repeated boilerplate pattern across ViewModels.
///
/// **Important:** All observation methods return a `Task` that the caller MUST store
/// and cancel when the observer is no longer needed (e.g., in `deinit` or when the
/// view disappears). Failing to store the returned `Task` will cause a memory leak
/// because the async `for await` loop retains its closure indefinitely.
///
/// Example usage:
/// ```swift
/// private var observationTask: Task<Void, Never>?
///
/// func startObserving() {
///     observationTask = StateFlowObserver.observe(stateFlow, onSuccess: { ... })
/// }
///
/// deinit { observationTask?.cancel() }
/// ```
@MainActor
enum StateFlowObserver {

    /// Observe a Kotlin StateFlow and handle loading/success/error states.
    ///
    /// - Returns: A `Task` that the caller **must** store and cancel when observation
    ///   is no longer needed. Discarding this task leaks the observation loop.
    /// - Parameters:
    ///   - stateFlow: The Kotlin StateFlow to observe
    ///   - onLoading: Called when state is ApiResultLoading
    ///   - onSuccess: Called when state is ApiResultSuccess with the data
    ///   - onError: Called when state is ApiResultError with parsed message
    ///   - resetState: Optional closure to reset the StateFlow state after handling
    static func observe<T>(
        _ stateFlow: SkieSwiftStateFlow<ApiResult<T>>,
        onLoading: (() -> Void)? = nil,
        onSuccess: @escaping (T) -> Void,
        onError: ((String) -> Void)? = nil,
        resetState: (() -> Void)? = nil
    ) -> Task<Void, Never> {
        let task = Task {
            for await state in stateFlow {
                if state is ApiResultLoading {
                    await MainActor.run {
                        onLoading?()
                    }
                } else if let success = state as? ApiResultSuccess<T> {
                    await MainActor.run {
                        if let data = success.data {
                            onSuccess(data)
                        }
                    }
                    resetState?()
                    break
                } else if let error = ApiResultBridge.error(from: state) {
                    await MainActor.run {
                        let message = ErrorMessageParser.parse(error.message)
                        onError?(message)
                    }
                    resetState?()
                    break
                } else if state is ApiResultIdle {
                    // Idle state, continue observing
                    continue
                }
            }
        }
        return task
    }

    /// Observe a StateFlow with automatic isLoading and errorMessage binding.
    /// Use this when you want standard loading/error state management.
    ///
    /// - Returns: A `Task` that the caller **must** store and cancel when observation
    ///   is no longer needed. Discarding this task leaks the observation loop.
    /// - Parameters:
    ///   - stateFlow: The Kotlin StateFlow to observe
    ///   - loadingSetter: Closure to set loading state
    ///   - errorSetter: Closure to set error message
    ///   - onSuccess: Called when state is ApiResultSuccess with the data
    ///   - resetState: Optional closure to reset the StateFlow state
    static func observeWithState<T>(
        _ stateFlow: SkieSwiftStateFlow<ApiResult<T>>,
        loadingSetter: @escaping (Bool) -> Void,
        errorSetter: @escaping (String?) -> Void,
        onSuccess: @escaping (T) -> Void,
        resetState: (() -> Void)? = nil
    ) -> Task<Void, Never> {
        return observe(
            stateFlow,
            onLoading: {
                loadingSetter(true)
            },
            onSuccess: { data in
                loadingSetter(false)
                onSuccess(data)
            },
            onError: { error in
                loadingSetter(false)
                errorSetter(error)
            },
            resetState: resetState
        )
    }

    /// Observe a StateFlow with a completion callback.
    /// Use this for create/update/delete operations that need success/failure feedback.
    ///
    /// - Returns: A `Task` that the caller **must** store and cancel when observation
    ///   is no longer needed. Discarding this task leaks the observation loop.
    /// - Parameters:
    ///   - stateFlow: The Kotlin StateFlow to observe
    ///   - loadingSetter: Closure to set loading state
    ///   - errorSetter: Closure to set error message
    ///   - onSuccess: Called when state is ApiResultSuccess with the data
    ///   - completion: Called with true on success, false on error
    ///   - resetState: Optional closure to reset the StateFlow state
    static func observeWithCompletion<T>(
        _ stateFlow: SkieSwiftStateFlow<ApiResult<T>>,
        loadingSetter: @escaping (Bool) -> Void,
        errorSetter: @escaping (String?) -> Void,
        onSuccess: ((T) -> Void)? = nil,
        completion: @escaping (Bool) -> Void,
        resetState: (() -> Void)? = nil
    ) -> Task<Void, Never> {
        return observe(
            stateFlow,
            onLoading: {
                loadingSetter(true)
            },
            onSuccess: { data in
                loadingSetter(false)
                onSuccess?(data)
                completion(true)
            },
            onError: { error in
                loadingSetter(false)
                errorSetter(error)
                completion(false)
            },
            resetState: resetState
        )
    }
}
