import 'package:graphql_flutter/graphql_flutter.dart';
import 'package:injectable/injectable.dart';
import 'package:krow/core/application/clients/api/api_client.dart';
import 'package:krow/core/application/clients/api/api_exception.dart';
import 'package:krow/core/data/models/pagination_wrapper/pagination_wrapper.dart';
import 'package:krow/features/shifts/data/models/staff_shift.dart';
import 'package:krow/features/shifts/data/shifts_gql.dart';

@Injectable()
class ShiftsApiProvider {
  final ApiClient _client;

  ShiftsApiProvider({required ApiClient client}) : _client = client;

  Future<PaginationWrapper> fetchShifts(String status, {String? after}) async {
    final QueryResult result = await _client.query(
      schema: getShiftsQuery,
      body: {'status': status, 'first': 100, 'after': after},
    );

    if (result.hasException) {
      throw Exception(result.exception.toString());
    }

    return PaginationWrapper.fromJson(
      result.data!['staff_shifts'],
      (json) => StaffShift.fromJson(json),
    );
  }

  Future<PaginationWrapper> getMissBreakFinishedShift() async {
    final QueryResult result = await _client.query(
      schema: staffNoBreakShifts,
      body: {'first': 100},
    );

    if (result.hasException) {
      throw Exception(result.exception.toString());
    }
    return PaginationWrapper.fromJson(
      result.data!['staff_no_break_shifts'],
      (json) => StaffShift.fromJson(json),
    );
  }

  Future<void> confirmShift(String id) async {
    final QueryResult result =
        await _client.mutate(schema: acceptShiftMutation, body: {'id': id});
    if (result.hasException) {
      throw parseBackendError(result.exception);
    }
  }

  Future<void> clockInShift(String id) async {
    final QueryResult result =
        await _client.mutate(schema: trackStaffClockin, body: {'id': id});
    if (result.hasException) {
      throw parseBackendError(result.exception);
    }
  }

  Future<void> completeShift(String id,
      {String? breakIn, String? breakOut, bool isPast = false}) async {
    final QueryResult result = await _client.mutate(
        schema: isPast ? trackStaffBreak : completeShiftMutation,
        body: {'id': id, 'break_in': breakIn, 'break_out': breakOut});
    if (result.hasException) {
      throw parseBackendError(result.exception);
    }
  }

  Future<void> completeShiftNoBreak(String id,
      {String? reason, String? additionalReason}) async {
    final QueryResult result = await _client.mutate(
        schema: submitNoBreakStaffShiftMutation,
        body: {'id': id, 'reason': reason, 'details': additionalReason});
    if (result.hasException) {
      throw parseBackendError(result.exception);
    }
  }

  Future<void> declineShift(String id,
      {String? reason, String? additionalReason}) async {
    final QueryResult result = await _client.mutate(
        schema: declineStaffShiftMutation,
        body: {
          'position_id': id,
          'reason': reason,
          'details': additionalReason
        });
    if (result.hasException) {
      throw parseBackendError(result.exception);
    }
  }

  Future<void> cancelShift(String id,
      {String? reason, String? additionalReason}) async {
    final QueryResult result = await _client.mutate(
        schema: cancelStaffShiftMutation,
        body: {
          'position_id': id,
          'reason': reason,
          'details': additionalReason
        });
    if (result.hasException) {
      throw parseBackendError(result.exception);
    }
  }

  Future<StaffShift> getShiftById(String id) async {
    final QueryResult result = await _client.query(
      schema: getShiftPositionQuery,
      body: {'id': id},
    );

    if (result.hasException) {
      throw parseBackendError(result.exception);
    }
    if (result.data == null || result.data!['staff_shift'] == null) {
      throw Exception('No data found');
    }
    return StaffShift.fromJson(result.data!['staff_shift']);
  }
}
