import '../../../../core/constants/api_endpoints.dart';
import '../../../../core/errors/exceptions.dart';
import '../../../../core/network/api_client.dart';
import '../../../../core/network/api_response.dart';
import '../models/create_product_warehouse_request.dart';
import '../models/product_detail_request_model.dart';
import '../models/product_model.dart';
import '../models/product_stage_model.dart';

/// Abstract interface for products remote data source
abstract class ProductsRemoteDataSource {
  /// Fetch products from the API
  ///
  /// [warehouseId] - The ID of the warehouse
  /// [type] - The operation type ('import' or 'export')
  ///
  /// Returns List<ProductModel>
  /// Throws [ServerException] if the API call fails
  Future<List<ProductModel>> getProducts(int warehouseId, String type);

  /// Get product stages for a product in a warehouse
  ///
  /// [request] - Request containing warehouseId and productId
  ///
  /// Returns List<ProductStageModel> with all stages for the product
  /// Throws [ServerException] if the API call fails
  Future<List<ProductStageModel>> getProductDetail(ProductDetailRequestModel request);

  /// Create product warehouse entry (import/export operation)
  ///
  /// [request] - Request containing all product warehouse details
  ///
  /// Returns void on success
  /// Throws [ServerException] if the API call fails
  Future<void> createProductWarehouse(CreateProductWarehouseRequest request);
}

/// Implementation of ProductsRemoteDataSource using ApiClient
class ProductsRemoteDataSourceImpl implements ProductsRemoteDataSource {
  final ApiClient apiClient;

  ProductsRemoteDataSourceImpl(this.apiClient);

  @override
  Future<List<ProductModel>> getProducts(int warehouseId, String type) async {
    try {
      // Choose endpoint based on operation type
      final endpoint = type == 'export'
          ? ApiEndpoints.productsForExport(warehouseId)
          : ApiEndpoints.products;

      // Make API call to get products
      final response = await apiClient.get(endpoint);

      // Parse the API response using ApiResponse wrapper
      final apiResponse = ApiResponse.fromJson(
        response.data as Map<String, dynamic>,
        (json) => (json as List)
            .map((e) => ProductModel.fromJson(e as Map<String, dynamic>))
            .toList(),
      );

      // Check if the API call was successful
      if (apiResponse.isSuccess && apiResponse.value != null) {
        return apiResponse.value!;
      } else {
        // Throw exception with error message from API
        throw ServerException(
          apiResponse.errors.isNotEmpty
              ? apiResponse.errors.first
              : 'Failed to get products',
        );
      }
    } catch (e) {
      // Re-throw ServerException as-is
      if (e is ServerException) {
        rethrow;
      }
      // Re-throw NetworkException as-is
      if (e is NetworkException) {
        rethrow;
      }
      // Wrap other exceptions in ServerException
      throw ServerException('Failed to get products: ${e.toString()}');
    }
  }

  @override
  Future<List<ProductStageModel>> getProductDetail(
      ProductDetailRequestModel request) async {
    try {
      // Make API call to get product stages
      final response = await apiClient.post(
        ApiEndpoints.productDetail,
        data: request.toJson(),
      );

      // Parse the API response - the Value field contains a list of stage objects
      final apiResponse = ApiResponse.fromJson(
        response.data as Map<String, dynamic>,
        (json) {
          // The API returns a list of stages for the product
          final list = json as List;
          if (list.isEmpty) {
            throw const ServerException('Không tìm thấy sản phẩm');
          }
          // Parse all stages from the list
          return list
              .map((e) => ProductStageModel.fromJson(e as Map<String, dynamic>))
              .toList();
        },
      );

      // Check if the API call was successful
      if (apiResponse.isSuccess && apiResponse.value != null) {
        return apiResponse.value!;
      } else {
        // Throw exception with error message from API
        throw ServerException(
          apiResponse.errors.isNotEmpty
              ? apiResponse.errors.first
              : 'Failed to get product stages',
        );
      }
    } catch (e) {
      // Re-throw ServerException as-is
      if (e is ServerException) {
        rethrow;
      }
      // Re-throw NetworkException as-is
      if (e is NetworkException) {
        rethrow;
      }
      // Wrap other exceptions in ServerException
      throw ServerException('Failed to get product stages: ${e.toString()}');
    }
  }

  @override
  Future<void> createProductWarehouse(
      CreateProductWarehouseRequest request) async {
    try {
      // The API expects an array of requests
      final requestData = [request.toJson()];

      // Make API call to create product warehouse
      final response = await apiClient.post(
        ApiEndpoints.createProductWarehouse,
        data: requestData,
      );

      // Parse the API response
      final apiResponse = ApiResponse.fromJson(
        response.data as Map<String, dynamic>,
        (json) => json, // We don't need to parse the response value
      );

      // Check if the API call was successful
      if (!apiResponse.isSuccess) {
        // Throw exception with error message from API
        throw ServerException(
          apiResponse.errors.isNotEmpty
              ? apiResponse.errors.first
              : 'Failed to create product warehouse entry',
        );
      }
    } catch (e) {
      // Re-throw ServerException as-is
      if (e is ServerException) {
        rethrow;
      }
      // Re-throw NetworkException as-is
      if (e is NetworkException) {
        rethrow;
      }
      // Wrap other exceptions in ServerException
      throw ServerException(
          'Failed to create product warehouse entry: ${e.toString()}');
    }
  }
}
