import 'package:firebase_data_connect/firebase_data_connect.dart' as fdc;
import 'package:krow_data_connect/krow_data_connect.dart' as dc;
import 'package:krow_domain/krow_domain.dart';
import '../../domain/repositories/home_repository_interface.dart';

/// Implementation of [HomeRepositoryInterface] that delegates to [HomeRepositoryMock].
///
/// This implementation resides in the data layer and acts as a bridge between the
/// domain layer and the data source (in this case, a mock from data_connect).
class HomeRepositoryImpl implements HomeRepositoryInterface {
  /// Creates a [HomeRepositoryImpl].
  HomeRepositoryImpl(this._service);
  final dc.DataConnectService _service;

  @override
  Future<HomeDashboardData> getDashboardData() async {
    return _service.run(() async {
      final String businessId = await _service.getBusinessId();

      final DateTime now = DateTime.now();
      final int daysFromMonday = now.weekday - DateTime.monday;
      final DateTime monday =
          DateTime(now.year, now.month, now.day).subtract(Duration(days: daysFromMonday));
      final DateTime weekRangeStart = DateTime(monday.year, monday.month, monday.day);
      final DateTime weekRangeEnd =
          DateTime(monday.year, monday.month, monday.day + 13, 23, 59, 59, 999);
      final fdc.QueryResult<dc.GetCompletedShiftsByBusinessIdData,
              dc.GetCompletedShiftsByBusinessIdVariables> completedResult =
          await _service.connector
              .getCompletedShiftsByBusinessId(
                businessId: businessId,
                dateFrom: _service.toTimestamp(weekRangeStart),
                dateTo: _service.toTimestamp(weekRangeEnd),
              )
              .execute();

      double weeklySpending = 0.0;
      double next7DaysSpending = 0.0;
      int weeklyShifts = 0;
      int next7DaysScheduled = 0;
      for (final dc.GetCompletedShiftsByBusinessIdShifts shift in completedResult.data.shifts) {
        final DateTime? shiftDate = shift.date?.toDateTime();
        if (shiftDate == null) {
          continue;
        }
        final int offset = shiftDate.difference(weekRangeStart).inDays;
        if (offset < 0 || offset > 13) {
          continue;
        }
        final double cost = shift.cost ?? 0.0;
        if (offset <= 6) {
          weeklySpending += cost;
          weeklyShifts += 1;
        } else {
          next7DaysSpending += cost;
          next7DaysScheduled += 1;
        }
      }

      final DateTime start = DateTime(now.year, now.month, now.day);
      final DateTime end = DateTime(now.year, now.month, now.day, 23, 59, 59, 999);

      final fdc.QueryResult<dc.ListShiftRolesByBusinessAndDateRangeData,
              dc.ListShiftRolesByBusinessAndDateRangeVariables> result =
          await _service.connector
              .listShiftRolesByBusinessAndDateRange(
                businessId: businessId,
                start: _service.toTimestamp(start),
                end: _service.toTimestamp(end),
              )
              .execute();

      int totalNeeded = 0;
      int totalFilled = 0;
      for (final dc.ListShiftRolesByBusinessAndDateRangeShiftRoles shiftRole
          in result.data.shiftRoles) {
        totalNeeded += shiftRole.count;
        totalFilled += shiftRole.assigned ?? 0;
      }

      return HomeDashboardData(
        weeklySpending: weeklySpending,
        next7DaysSpending: next7DaysSpending,
        weeklyShifts: weeklyShifts,
        next7DaysScheduled: next7DaysScheduled,
        totalNeeded: totalNeeded,
        totalFilled: totalFilled,
      );
    });
  }

  @override
  UserSessionData getUserSessionData() {
    final dc.ClientSession? session = dc.ClientSessionStore.instance.session;
    return UserSessionData(
      businessName: session?.business?.businessName ?? '',
      photoUrl: null, // Business photo isn't currently in session
    );
  }

  @override
  Future<List<ReorderItem>> getRecentReorders() async {
    return _service.run(() async {
      final String businessId = await _service.getBusinessId();

      final DateTime now = DateTime.now();
      final DateTime start = now.subtract(const Duration(days: 30));
      final fdc.Timestamp startTimestamp = _service.toTimestamp(start);
      final fdc.Timestamp endTimestamp = _service.toTimestamp(now);

      final fdc.QueryResult<dc.ListShiftRolesByBusinessDateRangeCompletedOrdersData,
              dc.ListShiftRolesByBusinessDateRangeCompletedOrdersVariables> result =
          await _service.connector
              .listShiftRolesByBusinessDateRangeCompletedOrders(
                businessId: businessId,
                start: startTimestamp,
                end: endTimestamp,
              )
              .execute();

      return result.data.shiftRoles
          .map((
            dc.ListShiftRolesByBusinessDateRangeCompletedOrdersShiftRoles shiftRole,
          ) {
            final String location = shiftRole.shift.location ?? shiftRole.shift.locationAddress ?? '';
            final String type = shiftRole.shift.order.orderType.stringValue;
            return ReorderItem(
              orderId: shiftRole.shift.order.id,
              title: '${shiftRole.role.name} - ${shiftRole.shift.title}',
              location: location,
              hourlyRate: shiftRole.role.costPerHour,
              hours: shiftRole.hours ?? 0,
              workers: shiftRole.count,
              type: type,
            );
          })
          .toList();
    });
  }
}
