import 'package:dio/dio.dart';

/// Thin client for POST /api/events — the play-event lifecycle the
/// server uses for history, recommendation scoring, ListenBrainz
/// scrobbles, and (since #415) system-playlist rotation.
///
/// Mirrors the web events dispatcher's three calls. Best-effort by
/// contract: callers swallow errors — a missed event is acceptable
/// per the server spec's v1 stance, and the server's
/// auto-close-prior-open keeps history sane even if an ended/skipped
/// is lost.
class EventsApi {
  EventsApi(this._dio);
  final Dio _dio;

  /// POST play_started. Returns the server's play_event_id (used to
  /// close the row later), or null if the call failed / response was
  /// malformed. `source` tags the originating system playlist
  /// ('for_you' | 'discover') so the server advances that rotation;
  /// omit for library / user-playlist / radio plays.
  Future<String?> playStarted({
    required String trackId,
    required String clientId,
    String? source,
  }) async {
    final r = await _dio.post<Map<String, dynamic>>(
      '/api/events',
      data: {
        'type': 'play_started',
        'track_id': trackId,
        'client_id': clientId,
        if (source != null && source.isNotEmpty) 'source': source,
      },
    );
    return (r.data ?? const {})['play_event_id'] as String?;
  }

  Future<void> playEnded({
    required String playEventId,
    required int durationPlayedMs,
  }) async {
    await _dio.post<void>(
      '/api/events',
      data: {
        'type': 'play_ended',
        'play_event_id': playEventId,
        'duration_played_ms': durationPlayedMs,
      },
    );
  }

  Future<void> playSkipped({
    required String playEventId,
    required int positionMs,
  }) async {
    await _dio.post<void>(
      '/api/events',
      data: {
        'type': 'play_skipped',
        'play_event_id': playEventId,
        'position_ms': positionMs,
      },
    );
  }

  /// Replays a complete play that happened offline / on a flaky
  /// connection (#426 part B). One call: the server records start+end
  /// from `atIso` (the original play-start time) + durationPlayedMs,
  /// applies the canonical skip rule, and advances #415 rotation when
  /// source is a system playlist. Driven by the offline mutation
  /// queue, never the live path.
  Future<void> playOffline({
    required String trackId,
    required String clientId,
    required String atIso,
    required int durationPlayedMs,
    String? source,
  }) async {
    await _dio.post<void>(
      '/api/events',
      data: {
        'type': 'play_offline',
        'track_id': trackId,
        'client_id': clientId,
        'at': atIso,
        'duration_played_ms': durationPlayedMs,
        if (source != null && source.isNotEmpty) 'source': source,
      },
    );
  }
}
