import 'dart:convert'; import 'dart:io'; import 'package:http_parser/http_parser.dart'; import 'package:http/http.dart' as http; import 'package:mime/mime.dart'; import '../models/guild.dart'; import '../models/channel.dart'; import '../models/message.dart'; import '../models/user.dart'; import '../models/role.dart'; class ApiService { String _baseUrl = 'http://localhost:8443'; String? _token; ApiService({String? baseUrl}) { if (baseUrl != null) _baseUrl = baseUrl; } void setBaseUrl(String url) { _baseUrl = url; } void updateFromWsUrl(String wsUrl) { _baseUrl = wsUrl.replaceFirst('ws://', 'http://').replaceFirst('wss://', 'https://'); if (_baseUrl.endsWith('/ws')) { _baseUrl = _baseUrl.substring(0, _baseUrl.length - 3); } } Map get _headers => { 'Content-Type': 'application/json', if (_token != null) 'Authorization': 'Bearer $_token', }; Future healthCheck() async { try { final resp = await http.get( Uri.parse('$_baseUrl/api/health'), ).timeout(const Duration(seconds: 5)); return resp.statusCode == 200; } catch (_) { return false; } } Future> getGuilds(String userId) async { final resp = await http.get( Uri.parse('$_baseUrl/api/guilds?user_id=$userId'), headers: _headers, ); if (resp.statusCode != 200) throw Exception('Failed to load guilds'); final List data = jsonDecode(resp.body); return data.map((g) => Guild.fromJson(g)).toList(); } Future createGuild(String name, String ownerId, {String? description}) async { final resp = await http.post( Uri.parse('$_baseUrl/api/guilds'), headers: _headers, body: jsonEncode({ 'name': name, 'owner_id': ownerId, 'description': description ?? '', }), ); if (resp.statusCode != 201) throw Exception('Failed to create guild'); final data = jsonDecode(resp.body); return data['id'] as String; } Future> getGuild(String guildId) async { final resp = await http.get( Uri.parse('$_baseUrl/api/guilds/$guildId'), headers: _headers, ); if (resp.statusCode != 200) throw Exception('Failed to load guild'); return jsonDecode(resp.body); } Future createChannel({ required String guildId, required String name, String type = 'text', String? categoryId, String? topic, }) async { final resp = await http.post( Uri.parse('$_baseUrl/api/channels'), headers: _headers, body: jsonEncode({ 'guild_id': guildId, 'category_id': categoryId ?? '', 'name': name, 'type': type, 'topic': topic ?? '', 'position': 0, }), ); if (resp.statusCode != 201) throw Exception('Failed to create channel'); return Channel.fromJson(jsonDecode(resp.body)); } Future> getMessages(String channelId, {int limit = 50, String? before}) async { final params = 'channel_id=$channelId&limit=$limit${before != null ? '&before=$before' : ''}'; final resp = await http.get( Uri.parse('$_baseUrl/api/messages?$params'), headers: _headers, ); if (resp.statusCode != 200) throw Exception('Failed to load messages'); final List data = jsonDecode(resp.body); return data.map((m) => Message.fromJson(m)).toList(); } Future uploadFile(File file) async { final uri = Uri.parse('$_baseUrl/api/upload'); final request = http.MultipartRequest('POST', uri); final mimeType = lookupMimeType(file.path) ?? 'application/octet-stream'; final parts = mimeType.split('/'); request.files.add(await http.MultipartFile.fromPath( 'file', file.path, contentType: MediaType(parts[0], parts[1]), )); if (_token != null) request.headers['Authorization'] = 'Bearer $_token'; final resp = await request.send(); if (resp.statusCode != 200) throw Exception('Upload failed'); final data = jsonDecode(await resp.stream.bytesToString()); return data['url'] as String; } Future getUser(String userId) async { final resp = await http.get( Uri.parse('$_baseUrl/api/users/$userId'), headers: _headers, ); if (resp.statusCode != 200) throw Exception('Failed to load user'); return User.fromJson(jsonDecode(resp.body)); } Future createRole({ required String guildId, required String name, int color = 0, List? permissions, }) async { final resp = await http.post( Uri.parse('$_baseUrl/api/roles/'), headers: _headers, body: jsonEncode({ 'guild_id': guildId, 'name': name, 'color': color, 'position': 0, 'permissions': permissions ?? [], }), ); if (resp.statusCode != 201) throw Exception('Failed to create role'); return Role.fromJson(jsonDecode(resp.body)); } }