import 'dart:developer';

import 'package:dartz/dartz.dart' hide Order;
import 'package:injectable/injectable.dart' hide Order;

import '../../../domain/order/order.dart';
import '../datasources/remote_data_provider.dart';
import '../order_dtos.dart';

@Injectable(as: IOrderRepository)
class OrderRepository implements IOrderRepository {
  final OrderRemoteDataProvider _dataProvider;
  final _logName = 'OrderRepository';

  OrderRepository(this._dataProvider);

  @override
  Future<Either<OrderFailure, ListOrder>> getOrders({
    int page = 1,
    int limit = 10,
    String status = 'completed',
    required DateTime startDate,
    required DateTime endDate,
    String? search,
  }) async {
    try {
      final result = await _dataProvider.fetchOrders(
        page: page,
        limit: limit,
        status: status,
        startDate: startDate,
        endDate: endDate,
        search: search,
      );

      if (result.hasError) {
        return left(result.error!);
      }

      final orders = result.data!.toDomain();
      return right(orders);
    } catch (e) {
      log('getOrdersError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }

  @override
  Future<Either<OrderFailure, Order>> createOrder({
    required OrderRequest request,
  }) async {
    try {
      final result = await _dataProvider.storeOrder(
        request: OrderRequestDto.fromDomain(request),
      );

      if (result.hasError) {
        return left(result.error!);
      }

      final order = result.data!.toDomain();
      return right(order);
    } catch (e) {
      log('createOrderError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }

  @override
  Future<Either<OrderFailure, Order>> createOrderWithPayment({
    required OrderRequest request,
    required String paymentMethodId,
  }) async {
    try {
      final result = await _dataProvider.storeWithPaymentOrder(
        request: OrderRequestDto.fromDomain(request),
        paymentMethodId: paymentMethodId,
      );

      if (result.hasError) {
        return left(result.error!);
      }

      final order = result.data!.toDomain();
      return right(order);
    } catch (e) {
      log('createOrderError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }

  @override
  Future<Either<OrderFailure, Order>> getOrderById(String id) async {
    try {
      final result = await _dataProvider.fetchOrderById(id);

      if (result.hasError) {
        return left(result.error!);
      }

      final order = result.data!.toDomain();
      return right(order);
    } catch (e) {
      log('getOrderByIdError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }

  @override
  Future<Either<OrderFailure, Order>> addItemOrder({
    required String id,
    required List<AddItemOrderRequest> request,
    String? idempotencyKey,
  }) async {
    try {
      final result = await _dataProvider.addItemOrder(
        id: id,
        request: request
            .map((e) => AddItemOrderRequestDto.fromDomain(e))
            .toList(),
        idempotencyKey: idempotencyKey,
      );

      if (result.hasError) {
        return left(result.error!);
      }

      final order = result.data!.toDomain();
      return right(order);
    } catch (e) {
      log('addItemOrderError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }

  @override
  Future<Either<OrderFailure, Payment>> createPayment({
    required PaymentRequest request,
    String? idempotencyKey,
  }) async {
    try {
      final result = await _dataProvider.storePayment(
        PaymentRequestDto.fromDomain(request),
        idempotencyKey: idempotencyKey,
      );

      if (result.hasError) {
        return left(result.error!);
      }

      final payment = result.data!.toDomain();
      return right(payment);
    } catch (e) {
      log('createPaymentError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }

  @override
  Future<Either<OrderFailure, Unit>> voidOrder({
    required String orderId,
    required String reason,
    String type = "ITEM",
    required List<OrderItem> orderItems,
    String? idempotencyKey,
  }) async {
    try {
      final result = await _dataProvider.voidOrder(
        orderId: orderId,
        reason: reason,
        type: type,
        orderItems: orderItems.map((e) => OrderItemDto.fromDomain(e)).toList(),
        idempotencyKey: idempotencyKey,
      );

      if (result.hasError) {
        return left(result.error!);
      }

      return right(unit);
    } catch (e) {
      log('voidOrderError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }

  @override
  Future<Either<OrderFailure, Payment>> createSplitBill(
    PaymentSplitBillRequest request, {
    String? idempotencyKey,
  }) async {
    try {
      final result = await _dataProvider.createSplitBill(
        PaymentSplitBillRequestDto.fromDomain(request),
        idempotencyKey: idempotencyKey,
      );

      if (result.hasError) {
        return left(result.error!);
      }

      final payment = result.data!.toDomain();
      return right(payment);
    } catch (e) {
      log('createSplitBillError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }

  @override
  Future<Either<OrderFailure, Unit>> refundOrder({
    required String id,
    required String reason,
    required int refundAmount,
    String? idempotencyKey,
  }) async {
    try {
      final result = await _dataProvider.refundPayment(
        id: id,
        reason: reason,
        refundAmount: refundAmount,
        idempotencyKey: idempotencyKey,
      );
      if (result.hasError) {
        return left(result.error!);
      }
      return right(unit);
    } catch (e) {
      log('refundOrderError', name: _logName, error: e);
      return left(const OrderFailure.unexpectedError());
    }
  }
}
