import 'package:dio/dio.dart';

import '../../models/playlist.dart';

/// Wire shape for GET /api/playlists. Server splits owned vs. public so
/// the UI can present them as different sections; we preserve that split
/// to give the integrations page room to grow.
class PlaylistsList {
  const PlaylistsList({required this.owned, required this.public});
  final List<Playlist> owned;
  final List<Playlist> public;

  factory PlaylistsList.empty() =>
      const PlaylistsList(owned: [], public: []);

  /// Concatenated view for callers that don't care about the split.
  List<Playlist> get all => [...owned, ...public];
}

class PlaylistsApi {
  PlaylistsApi(this._dio);
  final Dio _dio;

  /// GET /api/playlists?kind=user|system|all. Server returns
  /// `{"owned": [...], "public": [...]}`. Owned is the caller's own
  /// playlists, filtered by the kind param (default "user"). Public
  /// is other users' shared playlists; not filtered by kind.
  Future<PlaylistsList> list({String kind = 'user'}) async {
    final r = await _dio.get<Map<String, dynamic>>(
      '/api/playlists',
      queryParameters: {'kind': kind},
    );
    final body = r.data ?? const <String, dynamic>{};
    List<Playlist> parse(String key) {
      final raw = (body[key] as List?) ?? const [];
      return raw
          .map((e) => Playlist.fromJson((e as Map).cast<String, dynamic>()))
          .toList(growable: false);
    }
    return PlaylistsList(owned: parse('owned'), public: parse('public'));
  }

  Future<PlaylistDetail> get(String id) async {
    final r = await _dio.get<Map<String, dynamic>>('/api/playlists/$id');
    return PlaylistDetail.fromJson(r.data ?? const {});
  }

  /// GET /api/playlists/system/{kind}/shuffle (#415 / #411 R2).
  /// Same shape as get() but tracks are server-ordered rotation-aware
  /// (unplayed-this-rotation first; resets when exhausted). {kind} is
  /// the raw system_variant. Intentionally uncached — varies per play.
  Future<PlaylistDetail> systemShuffle(String variant) async {
    final r = await _dio.get<Map<String, dynamic>>(
      '/api/playlists/system/$variant/shuffle',
    );
    return PlaylistDetail.fromJson(r.data ?? const {});
  }

  /// POST /api/playlists/{id}/tracks. Owner only; server returns the
  /// playlist detail with the new rows.
  Future<void> appendTracks(String playlistId, List<String> trackIds) async {
    await _dio.post<void>(
      '/api/playlists/$playlistId/tracks',
      data: {'track_ids': trackIds},
    );
  }

  /// POST /api/playlists/system/{kind}/refresh (#411 R2). Rebuilds
  /// the caller's system playlists and returns the named kind's new
  /// playlist id, or null when the library is empty. {kind} is the
  /// raw system_variant — the server routes generically off the
  /// kind registry, no hyphen mapping.
  Future<String?> refreshSystem(String variant) async {
    final r = await _dio.post<Map<String, dynamic>>(
      '/api/playlists/system/$variant/refresh',
      data: const <String, dynamic>{},
    );
    return (r.data ?? const {})['playlist_id'] as String?;
  }
}
