import 'package:firebase_data_connect/firebase_data_connect.dart';
import 'package:krow_data_connect/krow_data_connect.dart';
import 'package:krow_domain/krow_domain.dart';

import '../../domain/repositories/personal_info_repository_interface.dart';

/// Implementation of [PersonalInfoRepositoryInterface] that delegates
/// to Firebase Data Connect for all data operations.
///
/// This implementation follows Clean Architecture by:
/// - Implementing the domain's repository interface
/// - Delegating all data access to the data_connect layer
/// - Mapping between data_connect DTOs and domain entities
/// - Containing no business logic
class PersonalInfoRepositoryImpl
    implements PersonalInfoRepositoryInterface {
  /// Creates a [PersonalInfoRepositoryImpl].
  ///
  /// Requires the Firebase Data Connect service.
  PersonalInfoRepositoryImpl({
    DataConnectService? service,
  }) : _service = service ?? DataConnectService.instance;

  final DataConnectService _service;

  @override
  Future<Staff> getStaffProfile() async {
    return _service.run(() async {
      final String uid = _service.auth.currentUser!.uid;

      // Query staff data from Firebase Data Connect
      final QueryResult<GetStaffByUserIdData, GetStaffByUserIdVariables> result =
          await _service.connector.getStaffByUserId(userId: uid).execute();

      if (result.data.staffs.isEmpty) {
        throw const ServerException(technicalMessage: 'Staff profile not found');
      }

      final GetStaffByUserIdStaffs rawStaff = result.data.staffs.first;

      // Map from data_connect DTO to domain entity
      return _mapToStaffEntity(rawStaff);
    });
  }

  @override
  Future<Staff> updateStaffProfile(
      {required String staffId, required Map<String, dynamic> data}) async {
    return _service.run(() async {
      // Start building the update mutation
      UpdateStaffVariablesBuilder updateBuilder =
          _service.connector.updateStaff(id: staffId);

      // Apply updates from map if present
      if (data.containsKey('name')) {
        updateBuilder = updateBuilder.fullName(data['name'] as String);
      }
      if (data.containsKey('email')) {
        updateBuilder = updateBuilder.email(data['email'] as String);
      }
      if (data.containsKey('phone')) {
        updateBuilder = updateBuilder.phone(data['phone'] as String?);
      }
      if (data.containsKey('avatar')) {
        updateBuilder = updateBuilder.photoUrl(data['avatar'] as String?);
      }
      if (data.containsKey('preferredLocations')) {
        // After schema update and SDK regeneration, preferredLocations accepts List<String>
        updateBuilder = updateBuilder.preferredLocations(
            data['preferredLocations'] as List<String>);
      }

      // Execute the update
      final OperationResult<UpdateStaffData, UpdateStaffVariables> result =
          await updateBuilder.execute();

      if (result.data.staff_update == null) {
        throw const ServerException(
            technicalMessage: 'Failed to update staff profile');
      }

      // Fetch the updated staff profile to return complete entity
      return getStaffProfile();
    });
  }

  @override
  Future<String> uploadProfilePhoto(String filePath) async {
    // TODO: Implement photo upload to Firebase Storage
    // This will be implemented when Firebase Storage integration is ready
    throw UnimplementedError(
      'Photo upload not yet implemented. Will integrate with Firebase Storage.',
    );
  }

  /// Maps a data_connect Staff DTO to a domain Staff entity.
  ///
  /// This mapping isolates the domain from data layer implementation details.
  Staff _mapToStaffEntity(GetStaffByUserIdStaffs dto) {
    return Staff(
      id: dto.id,
      authProviderId: dto.userId,
      name: dto.fullName,
      email: dto.email ?? '',
      phone: dto.phone,
      avatar: dto.photoUrl,
      status: StaffStatus.active,
      address: dto.addres,
      totalShifts: dto.totalShifts,
      averageRating: dto.averageRating,
      onTimeRate: dto.onTimeRate,
      noShowCount: dto.noShowCount,
      cancellationCount: dto.cancellationCount,
      reliabilityScore: dto.reliabilityScore,
      // After schema update and SDK regeneration, preferredLocations is List<String>?
      preferredLocations: dto.preferredLocations,
    );
  }
}
