import 'package:dio/dio.dart'; import 'package:get_it/get_it.dart'; import 'package:injectable/injectable.dart'; import 'package:superport/core/constants/api_endpoints.dart'; import 'package:superport/core/errors/exceptions.dart'; import 'package:superport/data/datasources/remote/api_client.dart'; import 'package:superport/data/models/common/api_response.dart'; import 'package:superport/data/models/common/paginated_response.dart'; import 'package:superport/data/models/company/company_dto.dart'; import 'package:superport/data/models/company/company_list_dto.dart'; import 'package:superport/data/models/company/branch_dto.dart'; abstract class CompanyRemoteDataSource { Future> getCompanies({ int page = 1, int perPage = 20, String? search, bool? isActive, }); Future createCompany(CreateCompanyRequest request); Future getCompanyDetail(int id); Future getCompanyWithBranches(int id); Future updateCompany(int id, UpdateCompanyRequest request); Future deleteCompany(int id); Future> getCompanyNames(); Future> getCompaniesWithBranches(); Future checkDuplicateCompany(String name); Future> searchCompanies(String query); Future updateCompanyStatus(int id, bool isActive); // Branch related methods Future createBranch(int companyId, CreateBranchRequest request); Future getBranchDetail(int companyId, int branchId); Future updateBranch(int companyId, int branchId, UpdateBranchRequest request); Future deleteBranch(int companyId, int branchId); Future> getCompanyBranches(int companyId); } @LazySingleton(as: CompanyRemoteDataSource) class CompanyRemoteDataSourceImpl implements CompanyRemoteDataSource { final ApiClient _apiClient; CompanyRemoteDataSourceImpl(this._apiClient); @override Future> getCompanies({ int page = 1, int perPage = 20, String? search, bool? isActive, }) async { try { final queryParams = { 'page': page, 'per_page': perPage, if (search != null) 'search': search, if (isActive != null) 'is_active': isActive, }; final response = await _apiClient.get( ApiEndpoints.companies, queryParameters: queryParams, ); if (response.statusCode == 200) { final apiResponse = ApiResponse>.fromJson( response.data, (json) => PaginatedResponse.fromJson( json, (item) => CompanyListDto.fromJson(item), ), ); return apiResponse.data; } else { throw ApiException( message: 'Failed to load companies', statusCode: response.statusCode, ); } } catch (e) { if (e is ApiException) rethrow; throw ApiException(message: e.toString()); } } @override Future createCompany(CreateCompanyRequest request) async { try { final response = await _apiClient.post( ApiEndpoints.companies, data: request.toJson(), ); if (response.statusCode == 201) { final apiResponse = ApiResponse.fromJson( response.data, (json) => CompanyResponse.fromJson(json), ); return apiResponse.data; } else { throw ApiException( message: 'Failed to create company', statusCode: response.statusCode, ); } } catch (e) { if (e is ApiException) rethrow; throw ApiException(message: e.toString()); } } @override Future getCompanyDetail(int id) async { try { final response = await _apiClient.dio.get( '${ApiEndpoints.companies}/$id', ); return CompanyResponse.fromJson(response.data['data']); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to fetch company detail', code: e.response?.statusCode, ); } } @override Future getCompanyWithBranches(int id) async { try { final response = await _apiClient.dio.get( '${ApiEndpoints.companies}/$id/with-branches', ); return CompanyWithBranches.fromJson(response.data['data']); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to fetch company with branches', code: e.response?.statusCode, ); } } @override Future updateCompany(int id, UpdateCompanyRequest request) async { try { final response = await _apiClient.dio.put( '${ApiEndpoints.companies}/$id', data: request.toJson(), ); return CompanyResponse.fromJson(response.data['data']); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to update company', code: e.response?.statusCode, ); } } @override Future deleteCompany(int id) async { try { await _apiClient.dio.delete( '${ApiEndpoints.companies}/$id', ); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to delete company', code: e.response?.statusCode, ); } } @override Future> getCompanyNames() async { try { final response = await _apiClient.dio.get( '${ApiEndpoints.companies}/names', ); final List data = response.data['data']; return data.map((json) => CompanyNameDto.fromJson(json)).toList(); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to fetch company names', code: e.response?.statusCode, ); } } // Branch methods @override Future createBranch(int companyId, CreateBranchRequest request) async { try { final response = await _apiClient.dio.post( '${ApiEndpoints.companies}/$companyId/branches', data: request.toJson(), ); return BranchResponse.fromJson(response.data['data']); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to create branch', code: e.response?.statusCode, ); } } @override Future getBranchDetail(int companyId, int branchId) async { try { final response = await _apiClient.dio.get( '${ApiEndpoints.companies}/$companyId/branches/$branchId', ); return BranchResponse.fromJson(response.data['data']); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to fetch branch detail', code: e.response?.statusCode, ); } } @override Future updateBranch(int companyId, int branchId, UpdateBranchRequest request) async { try { final response = await _apiClient.dio.put( '${ApiEndpoints.companies}/$companyId/branches/$branchId', data: request.toJson(), ); return BranchResponse.fromJson(response.data['data']); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to update branch', code: e.response?.statusCode, ); } } @override Future deleteBranch(int companyId, int branchId) async { try { await _apiClient.dio.delete( '${ApiEndpoints.companies}/$companyId/branches/$branchId', ); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to delete branch', code: e.response?.statusCode, ); } } @override Future> getCompanyBranches(int companyId) async { try { final response = await _apiClient.dio.get( '${ApiEndpoints.companies}/$companyId/branches', ); final List data = response.data['data']; return data.map((json) => BranchListDto.fromJson(json)).toList(); } on DioException catch (e) { throw ServerException( message: e.response?.data['message'] ?? 'Failed to fetch company branches', code: e.response?.statusCode, ); } } @override Future> getCompaniesWithBranches() async { try { final response = await _apiClient.get('${ApiEndpoints.companies}/branches'); if (response.statusCode == 200) { final apiResponse = ApiResponse>.fromJson( response.data, (json) => (json as List) .map((item) => CompanyWithBranches.fromJson(item)) .toList(), ); return apiResponse.data; } else { throw ApiException( message: 'Failed to load companies with branches', statusCode: response.statusCode, ); } } catch (e) { if (e is ApiException) rethrow; throw ApiException(message: e.toString()); } } @override Future checkDuplicateCompany(String name) async { try { final response = await _apiClient.get( '${ApiEndpoints.companies}/check-duplicate', queryParameters: {'name': name}, ); if (response.statusCode == 200) { final apiResponse = ApiResponse>.fromJson( response.data, (json) => json, ); return apiResponse.data['exists'] ?? false; } else { throw ApiException( message: 'Failed to check duplicate', statusCode: response.statusCode, ); } } catch (e) { if (e is ApiException) rethrow; throw ApiException(message: e.toString()); } } @override Future> searchCompanies(String query) async { try { final response = await _apiClient.get( '${ApiEndpoints.companies}/search', queryParameters: {'q': query}, ); if (response.statusCode == 200) { final apiResponse = ApiResponse>.fromJson( response.data, (json) => (json as List) .map((item) => CompanyListDto.fromJson(item)) .toList(), ); return apiResponse.data; } else { throw ApiException( message: 'Failed to search companies', statusCode: response.statusCode, ); } } catch (e) { if (e is ApiException) rethrow; throw ApiException(message: e.toString()); } } @override Future updateCompanyStatus(int id, bool isActive) async { try { final response = await _apiClient.patch( '${ApiEndpoints.companies}/$id/status', data: {'is_active': isActive}, ); if (response.statusCode != 200) { throw ApiException( message: 'Failed to update company status', statusCode: response.statusCode, ); } } catch (e) { if (e is ApiException) rethrow; throw ApiException(message: e.toString()); } } }