import 'dart:developer';
import 'dart:ui';

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

import '../../../domain/table/table.dart';
import '../../outlet/datasources/local_data_provider.dart';
import '../datasources/remote_data_provider.dart';

@Injectable(as: ITableRepository)
class TableRepository implements ITableRepository {
  final TableRemoteDataProvider _remoteDataProvider;
  final OutletLocalDatasource _outletLocalDatasource;
  final _logName = 'TableRepository';

  TableRepository(this._remoteDataProvider, this._outletLocalDatasource);

  @override
  Future<Either<TableFailure, ListTable>> fetchTables({
    int page = 1,
    int limit = 50,
    String? status,
  }) async {
    try {
      final result = await _remoteDataProvider.fetchTables(
        page: page,
        limit: limit,
        status: status,
      );

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

      final tables = result.data!.toDomain();

      return right(tables);
    } catch (e) {
      log('fetchTables', name: _logName, error: e);
      return left(const TableFailure.unexpectedError());
    }
  }

  @override
  Future<Either<TableFailure, Table>> createTable({
    required String name,
    required int capacity,
  }) async {
    try {
      final outlet = await _outletLocalDatasource.currentOutlet();

      final result = await _remoteDataProvider.storeTable(
        outletId: outlet.id,
        name: name,
        capacity: capacity,
      );

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

      final table = result.data!.toDomain();

      return right(table);
    } catch (e) {
      log('fetchCreateTable', name: _logName, error: e);
      return left(const TableFailure.unexpectedError());
    }
  }

  @override
  Future<Either<TableFailure, Table>> updatePosition({
    required String id,
    required Offset position,
  }) async {
    try {
      final result = await _remoteDataProvider.updatePosition(
        id: id,
        position: position,
      );

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

      final table = result.data!.toDomain();

      return right(table);
    } catch (e) {
      log('updatePositionTableError', name: _logName, error: e);
      return left(const TableFailure.unexpectedError());
    }
  }

  @override
  Future<Either<TableFailure, Unit>> transferTable({
    required String fromTableId,
    required String toTableId,
  }) async {
    try {
      final result = await _remoteDataProvider.transferTable(
        fromTableId: fromTableId,
        toTableId: toTableId,
      );

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

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