import 'dart:convert'; import 'package:http/http.dart' as http; import '../../config/api_config.dart'; import '../../services/auth_service.dart'; class SpellingWordsApiException implements Exception { SpellingWordsApiException(this.statusCode, this.body); final int statusCode; final String body; @override String toString() => 'SpellingWordsApiException($statusCode): $body'; } /// HTTP client for the shared spelling word catalog. class SpellingWordsRemoteStore { SpellingWordsRemoteStore({http.Client? client}) : _client = client ?? http.Client(); final http.Client _client; static const String _basePath = '/v1/me/spelling-words'; Future> fetchWords() async { final String? token = await AuthService.instance.getIdToken(); if (token == null) { throw StateError('Not signed in'); } final http.Response response = await _client.get( Uri.parse('$apiBaseUrl$_basePath'), headers: _authHeaders(token), ); if (response.statusCode != 200) { throw SpellingWordsApiException(response.statusCode, response.body); } final Map body = jsonDecode(response.body) as Map; final List words = body['words'] as List? ?? []; return words.map((dynamic w) => w as String).toList(growable: false); } Future> addWord(String word) async { final String? token = await AuthService.instance.getIdToken(); if (token == null) { throw StateError('Not signed in'); } final http.Response response = await _client.post( Uri.parse('$apiBaseUrl$_basePath'), headers: _authHeaders(token), body: jsonEncode({'word': word}), ); if (response.statusCode != 201) { throw SpellingWordsApiException(response.statusCode, response.body); } final Map body = jsonDecode(response.body) as Map; final List words = body['words'] as List? ?? []; return words.map((dynamic w) => w as String).toList(growable: false); } Future<({int added, int skipped})> importText(String text) async { final String? token = await AuthService.instance.getIdToken(); if (token == null) { throw StateError('Not signed in'); } final http.Response response = await _client.post( Uri.parse('$apiBaseUrl$_basePath/import'), headers: { ..._authHeaders(token), 'Content-Type': 'text/plain; charset=utf-8', }, body: text, ); if (response.statusCode != 200) { throw SpellingWordsApiException(response.statusCode, response.body); } final Map body = jsonDecode(response.body) as Map; return ( added: (body['added'] as num?)?.toInt() ?? 0, skipped: (body['skipped'] as num?)?.toInt() ?? 0, ); } Future exportText() async { final String? token = await AuthService.instance.getIdToken(); if (token == null) { throw StateError('Not signed in'); } final http.Response response = await _client.get( Uri.parse('$apiBaseUrl$_basePath/export'), headers: { 'Authorization': 'Bearer $token', 'Accept': 'text/plain', }, ); if (response.statusCode != 200) { throw SpellingWordsApiException(response.statusCode, response.body); } return response.body; } Map _authHeaders(String token) { return { 'Authorization': 'Bearer $token', 'Content-Type': 'application/json', 'Accept': 'application/json', }; } }