import 'package:dartz/dartz.dart';
import '../../../../core/errors/exceptions.dart';
import '../../../../core/errors/failures.dart';
import '../../domain/entities/product_entity.dart';
import '../../domain/entities/product_stage_entity.dart';
import '../../domain/repositories/products_repository.dart';
import '../datasources/products_local_datasource.dart';
import '../datasources/products_remote_datasource.dart';
import '../models/create_product_warehouse_request.dart';
import '../models/product_detail_request_model.dart';

/// Implementation of ProductsRepository
/// Handles data operations and error conversion
/// Uses local-first approach: loads from cache first, only fetches from API on explicit refresh
class ProductsRepositoryImpl implements ProductsRepository {
  final ProductsRemoteDataSource remoteDataSource;
  final ProductsLocalDataSource localDataSource;

  ProductsRepositoryImpl({
    required this.remoteDataSource,
    required this.localDataSource,
  });

  @override
  Future<Either<Failure, List<ProductEntity>>> getProducts(
    int warehouseId,
    String type, {
    bool forceRefresh = false,
  }) async {
    try {
      // If not forcing refresh, try to get from cache first
      if (!forceRefresh) {
        final cachedProducts =
            await localDataSource.getCachedProducts(warehouseId, type);

        // If we have cached data, return it immediately
        if (cachedProducts.isNotEmpty) {
          return Right(cachedProducts.map((model) => model.toEntity()).toList());
        }
      }

      // If forcing refresh or no cached data, fetch from remote
      final products = await remoteDataSource.getProducts(warehouseId, type);

      // Cache the fetched products for future use
      await localDataSource.cacheProducts(warehouseId, type, products);

      // Convert models to entities and return success
      return Right(products.map((model) => model.toEntity()).toList());
    } on ServerException catch (e) {
      // If remote fetch fails, try to return cached data as fallback
      if (forceRefresh) {
        final cachedProducts =
            await localDataSource.getCachedProducts(warehouseId, type);
        if (cachedProducts.isNotEmpty) {
          // Return cached data with a note that it might be outdated
          return Right(cachedProducts.map((model) => model.toEntity()).toList());
        }
      }
      // Convert ServerException to ServerFailure
      return Left(ServerFailure(e.message));
    } on NetworkException catch (e) {
      // If network fails, try to return cached data as fallback
      final cachedProducts =
          await localDataSource.getCachedProducts(warehouseId, type);
      if (cachedProducts.isNotEmpty) {
        // Return cached data when network is unavailable
        return Right(cachedProducts.map((model) => model.toEntity()).toList());
      }
      // Convert NetworkException to NetworkFailure
      return Left(NetworkFailure(e.message));
    } catch (e) {
      // Handle any other exceptions
      return Left(ServerFailure('Unexpected error: ${e.toString()}'));
    }
  }

  @override
  Future<Either<Failure, List<ProductStageEntity>>> getProductDetail(
    int warehouseId,
    int productId,
  ) async {
    try {
      // Create request model
      final request = ProductDetailRequestModel(
        warehouseId: warehouseId,
        productId: productId,
      );

      // Fetch product stages from remote data source
      final stages = await remoteDataSource.getProductDetail(request);

      // Convert models to entities and return success
      return Right(stages.map((stage) => stage.toEntity()).toList());
    } on ServerException catch (e) {
      // Convert ServerException to ServerFailure
      return Left(ServerFailure(e.message));
    } on NetworkException catch (e) {
      // Convert NetworkException to NetworkFailure
      return Left(NetworkFailure(e.message));
    } catch (e) {
      // Handle any other exceptions
      return Left(ServerFailure('Unexpected error: ${e.toString()}'));
    }
  }

  @override
  Future<Either<Failure, void>> createProductWarehouse(
    CreateProductWarehouseRequest request,
  ) async {
    try {
      // Call remote data source to create product warehouse
      await remoteDataSource.createProductWarehouse(request);

      // Return success
      return const Right(null);
    } on ServerException catch (e) {
      // Convert ServerException to ServerFailure
      return Left(ServerFailure(e.message));
    } on NetworkException catch (e) {
      // Convert NetworkException to NetworkFailure
      return Left(NetworkFailure(e.message));
    } catch (e) {
      // Handle any other exceptions
      return Left(ServerFailure('Unexpected error: ${e.toString()}'));
    }
  }
}
