import 'dart:convert'; import 'package:http/http.dart' as http; import '../models/models.dart'; abstract class ReportDataSource { Future> recommended(); Future> reports(); Future> institutions(); Future institutionDetail(String institutionId); Future> listen(); Future reportDetail(String reportId); Future moduleDetail(String reportId, String moduleId); } class RnbApiDataSource implements ReportDataSource { RnbApiDataSource({ http.Client? client, this.baseUrl = const String.fromEnvironment('RNB_API_BASE'), }) : client = client ?? http.Client(); final http.Client client; final String baseUrl; Future _get(String path) async { if (baseUrl.isEmpty) { throw StateError('RNB_API_BASE is required for live API requests.'); } final response = await client.get(Uri.parse('$baseUrl$path')); if (response.statusCode != 200) { throw StateError('Request failed: ${response.statusCode}'); } return jsonDecode(utf8.decode(response.bodyBytes)) as JsonMap; } List _items(JsonMap body) => asMapList(body['items']); @override Future> recommended() async { final body = await _get('/feed/recommended'); return _items(body).map(ReportCardModel.fromJson).toList(); } @override Future> reports() async { final body = await _get('/reports'); return _items(body).map(ReportCardModel.fromJson).toList(); } @override Future> institutions() async { final body = await _get('/institutions'); return _items(body).map(Institution.fromJson).toList(); } @override Future institutionDetail(String institutionId) async { return Institution.fromJson(await _get('/institutions/$institutionId')); } @override Future> listen() async { final body = await _get('/listen'); return _items(body).map(AudioItem.fromJson).toList(); } @override Future reportDetail(String reportId) async { return ReportDetail.fromJson(await _get('/reports/$reportId')); } @override Future moduleDetail(String reportId, String moduleId) async { return ModuleDetail.fromJson(await _get('/reports/$reportId/modules/$moduleId')); } }