import 'package:equatable/equatable.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/features/customers/models/customer_model.dart';
import 'package:flux/features/master_data/providers/models/provider_model.dart';
import 'package:flux/features/master_data/providers/models/provider_model_extensions.dart';
import 'package:flux/features/master_data/staff/models/staff_member_model.dart';
import 'package:flux/features/operations/data/operations_repository.dart';
import 'package:flux/features/operations/models/operation_model.dart';
import 'package:get_it/get_it.dart';
import 'package:uuid/uuid.dart';

part 'operation_form_state.dart';

class OperationFormCubit extends Cubit<OperationFormState> {
  final OperationsRepository _repository = GetIt.I<OperationsRepository>();
  final SessionCubit _sessionCubit = GetIt.I<SessionCubit>();
  final Uuid _uuid = const Uuid();

  OperationFormCubit({
    StaffMemberModel? createdBy,
    OperationModel? existingOperation,
  }) : super(
         OperationFormState(
           operation:
               existingOperation ??
               OperationModel.empty().copyWith(
                 staffId: createdBy?.id,
                 staffDisplayName: createdBy?.name,
               ),
         ),
       );

  Future<void> initForm({
    OperationModel? existingOperation,
    String? operationId,
  }) async {
    emit(state.copyWith(status: OperationFormStatus.loading));

    try {
      if (existingOperation != null) {
        emit(
          state.copyWith(
            operation: existingOperation,
            status: OperationFormStatus.ready,
          ),
        );
      } else if (operationId != null) {
        emit(state.copyWith(status: OperationFormStatus.loading));
        try {
          final operation = await _repository.fetchOperationById(operationId);
          emit(
            state.copyWith(
              operation: operation,
              status: OperationFormStatus.ready,
            ),
          );
        } on Exception catch (e) {
          emit(
            state.copyWith(
              status: OperationFormStatus.failure,
              errorMessage: e.toString(),
            ),
          );
        }
      } else {
        // NUOVA PRATICA: Creiamo un nuovo Batch UUID
        final currentStore = _sessionCubit.state.currentStore;
        final companyId = _sessionCubit.state.company?.id ?? '';
        final newOperation = state.operation.copyWith(
          companyId: companyId,
          storeId: currentStore?.id,
          status: OperationStatus.success,
          reference: '',
          batchUuid: _uuid.v4(),
        );
        emit(
          state.copyWith(
            operation: newOperation,
            status: OperationFormStatus.ready,
          ),
        );
      }
    } catch (e) {
      emit(
        state.copyWith(
          status: OperationFormStatus.failure,
          errorMessage: "Errore inizializzazione form: $e",
        ),
      );
    }
  }

  // --- LOGICA BATCH ---

  void _prepareNextOperationInBatch() {
    final current = state.operation;

    emit(
      state.copyWith(
        status: OperationFormStatus.ready,
        operation: OperationModel(
          companyId: current.companyId,
          storeId: current.storeId,
          storeDisplayName: current.storeDisplayName,
          // 🥷 REINSERIAMO LO STAFF (Il "colpevole" era qui)
          staffId: current.staffId,
          staffDisplayName: current.staffDisplayName,

          batchUuid: current.batchUuid,
          customerId: current.customerId,
          customer: current.customer,
          reference: current.reference,
          status: OperationStatus.draft,
          createdAt: DateTime.now(),
          // Mantieni isBusiness se vuoi che rimanga coerente col cliente
          isBusiness: current.isBusiness,
        ),
      ),
    );
  }

  // --- SALVATAGGIO ---

  Future<void> saveOperation({
    required OperationStatus targetStatus,
    required bool keepAdding,
  }) async {
    emit(
      state.copyWith(status: OperationFormStatus.saving, errorMessage: null),
    );

    try {
      OperationModel operationToSave = state.operation.copyWith(
        status: targetStatus,
      );
      if (operationToSave.reference.isEmpty) {
        if (operationToSave.customer != null &&
            operationToSave.customer!.phoneNumber.isNotEmpty) {
          operationToSave = operationToSave.copyWith(
            reference: '${operationToSave.customer?.phoneNumber} - auto',
          );
        } else {
          operationToSave = operationToSave.copyWith(
            reference: 'Nessun riferimento',
          );
        }
      }
      final savedOperation = await _repository.saveFullOperation(
        operation: operationToSave,
      );

      if (keepAdding) {
        // Salviamo nella "memoria" del batch le pratiche create finora
        final updatedBatchList = List<OperationModel>.from(
          state.savedBatchOperations,
        )..add(savedOperation);

        emit(
          state.copyWith(
            status: OperationFormStatus.successAndAddAnother,
            savedBatchOperations: updatedBatchList,
          ),
        );

        // Pulisce i campi per la prossima operazione
        _prepareNextOperationInBatch();
      } else {
        emit(
          state.copyWith(
            status: OperationFormStatus.success,
            operation: savedOperation, // Aggiorniamo con l'ID restituito dal DB
          ),
        );
      }
    } catch (e) {
      emit(
        state.copyWith(
          status: OperationFormStatus.failure,
          errorMessage: e.toString(),
        ),
      );
    }
  }

  Future<String?> saveOperationDraft() async {
    try {
      final operationToSave = state.operation;
      if (operationToSave.customerId == null ||
          operationToSave.customerId!.isEmpty) {
        throw Exception('Seleziona un cliente prima di poter usare il QR');
      }
      final savedOperation = await _repository.saveFullOperation(
        operation: operationToSave,
      );
      emit(
        state.copyWith(
          operation: savedOperation,
          status: OperationFormStatus.ready,
        ),
      );
      return savedOperation.id;
    } catch (e) {
      emit(
        state.copyWith(
          status: OperationFormStatus.failure,
          errorMessage: e.toString(),
        ),
      );
      return null;
    }
  }

  // --- GESTIONE DEI CAMPI IN TEMPO REALE ---

  void updateFields({
    String? reference,
    String? note,
    String? type,
    String? subType,
    String? description,
    DateTime? expirationDate,
    int? quantity,
    String? modelId,
    String? modelDisplayName,
    String? staffId,
    String? staffDisplayName,
    OperationStatus? status,
    bool? isBusiness,

    bool clearProvider = false,
    bool clearType = false,
    bool clearSubType = false,
    bool clearDescription = false,
    bool clearExpiration = false,
    bool clearQuantity = false,
    bool clearModel = false,
  }) {
    final current = state.operation;

    int? newQuantity;
    if (clearQuantity) newQuantity = 1;
    if (quantity != null && quantity <= 0) newQuantity = 0;
    if (quantity != null && quantity > 0) newQuantity = quantity;

    final updated = current.copyWith(
      reference: reference ?? current.reference,
      note: note ?? current.note,
      quantity: newQuantity ?? current.quantity,
      type: clearType ? null : (type ?? current.type),
      description: clearDescription
          ? null
          : (description ?? current.description),
      subType: clearSubType ? null : (subType ?? current.subType),
      expirationDate: clearExpiration
          ? null
          : (expirationDate ?? current.expirationDate),
      modelId: clearModel ? null : (modelId ?? current.modelId),
      modelDisplayName: clearModel
          ? null
          : (modelDisplayName ?? current.modelDisplayName),
      staffId: staffId ?? current.staffId,
      staffDisplayName: staffDisplayName ?? current.staffDisplayName,
      status: status ?? current.status,
      isBusiness: isBusiness ?? current.isBusiness,
    );

    emit(state.copyWith(operation: updated));
  }

  void updateProvider(ProviderModel? newProvider) {
    final current = state.operation;

    final updatedOperation = current.copyWith(
      // Se newProvider è null, passiamo una funzione che ritorna null per sbiancare i campi!
      providerId: () => newProvider?.id,
      provider: () => newProvider,
    );

    emit(state.copyWith(operation: updatedOperation));
  }

  void updateCustomer(CustomerModel customer) {
    final bool isBusiness = customer.isBusiness;
    final updatedOperation = state.operation.copyWith(
      customer: customer,
      customerId: customer.id,
      isBusiness: isBusiness,
    );
    emit(state.copyWith(operation: updatedOperation));
  }

  // --- UTILS ---

  void updateOperationType(
    String newType, {
    required List<ProviderModel> allProviders,
    String? defaultProviderId,
  }) {
    // 1. Aggiorniamo il tipo nel modello in canna
    // (Presumo tu abbia un metodo copyWith o simile)

    // 2. LA LOGICA DI DEFAULT
    if (defaultProviderId != null) {
      // Troviamo il provider di default nella lista
      final defaultProvider = allProviders
          .where((p) => p.id == defaultProviderId)
          .firstOrNull;

      if (defaultProvider != null) {
        // Usiamo l'extension appena creata!
        if (defaultProvider.supportsOperation(newType)) {
          updateProvider(defaultProvider);
        } else {
          // Se cambi tipo (es. da Mobile a Luce) e il default non lo supporta, sbianchiamo
          updateProvider(null);
        }
      }
    }
  }

  void setTypeWithSmartDefaults({
    required String newType,
    required List<ProviderModel> allProviders,
    String? defaultProviderId,
  }) {
    final currentOp = state.operation;

    // -----------------------------------------
    // 1. SMART DATES: Calcolo Scadenze Default (Invariato)
    // -----------------------------------------
    DateTime? defaultDate;
    final now = DateTime.now();

    if (newType == 'Energy') {
      defaultDate = DateTime(now.year, now.month + 24, now.day);
    }
    if (newType == 'Fin') {
      defaultDate = DateTime(now.year, now.month + 30, now.day);
    }
    if (newType == 'Entertainment') {
      defaultDate = DateTime(now.year, now.month + 12, now.day);
    }

    // -----------------------------------------
    // 2. SMART PROVIDER: Filtro e Auto-Selezione ad Oggetti
    // -----------------------------------------
    // Pescatore direttamente l'oggetto dal modello corrente
    ProviderModel? targetProvider = currentOp.provider;

    // A) Il provider attuale è ancora compatibile col nuovo tipo scelto?
    if (targetProvider != null && !targetProvider.supportsOperation(newType)) {
      // Non è più compatibile (es. da TIM fisso passo a Energy). Lo sbianchiamo!
      targetProvider = null;
    }

    // B) Se non c'è un provider selezionato, proviamo ad auto-inserire quello di default del negozio
    if (targetProvider == null && defaultProviderId != null) {
      final defaultProvider = allProviders
          .where((p) => p.id == defaultProviderId)
          .firstOrNull;

      // Controlliamo che il default del negozio supporti questa specifica operazione
      if (defaultProvider != null &&
          defaultProvider.supportsOperation(newType)) {
        targetProvider = defaultProvider;
      }
    }

    // -----------------------------------------
    // 3. EMISSIONE DELLO STATO PULITO
    // -----------------------------------------
    emit(
      state.copyWith(
        operation: currentOp.copyWith(
          type: newType,
          subType: '', // Resettiamo il sottotipo per evitare incongruenze
          expirationDate:
              defaultDate, // Impostiamo la scadenza di default se calcolata
          // 🥷 APPLICHIAMO IL TRUCCO NINJA DELLE FUNZIONI
          // Se targetProvider è null, le funzioni ritorneranno null sbiancando il DB!
          providerId: () => targetProvider?.id,
          provider: () => targetProvider,

          // Nota: Per azzerare davvero questi due, ricordati in futuro di applicare
          // il trucco delle funzioni anche a modelId e modelDisplayName nel modello!
          modelId: null,
          modelDisplayName: null,
        ),
      ),
    );
  }
}
