import 'package:flutter/material.dart';
import 'package:flux/core/blocs/session/session_cubit.dart';
import 'package:flux/core/enums_and_consts/consts.dart';
import 'package:flux/features/settings/document_sequence/data/document_sequence_repository.dart';
import 'package:flux/features/settings/document_sequence/models/document_sequence_model.dart';
import 'package:flux/features/tickets/models/ticket_model.dart';
import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart';

class TicketRepository {
  final SupabaseClient _supabase = GetIt.I.get<SupabaseClient>();
  final DocumentSequenceRepository _documentSequenceRepository = GetIt.I
      .get<DocumentSequenceRepository>();

  TicketRepository();

  static const String _tableName = Tables.tickets;

  // --- RECUPERO PAGINATO CON FILTRI E JOIN DEI TICKET DI UNO STORE ---
  Future<List<TicketModel>> fetchStoreTickets({
    required int offset,
    int limit = 50,
    String? searchTerm,
    DateTimeRange? dateRange,
    TicketStatus? statusFilter,
    TicketType? ticketTypeFilter,
    String? staffIdFilter,
  }) async {
    try {
      var query = _supabase
          .from(_tableName)
          .select('''
      *,
      customer:${Tables.customers}!ticket_customer_id_fkey (*),
      ${Tables.shippingDocuments} (*, ${Tables.attachments} (*)),
      created_by:${Tables.staffMembers}!ticket_staff_id_fkey (*),
      assigned_to:${Tables.staffMembers}!ticket_assigned_to_id_fkey (*),
      target_model:${Tables.models}!ticket_model_id_1_fkey (*),
      source_model:${Tables.models}!ticket_model_id_2_fkey (*)
    ''')
          .eq('store_id', GetIt.I.get<SessionCubit>().state.currentStore!.id!);

      // Filtro Range Date
      if (dateRange != null) {
        query = query
            .gte('created_at', dateRange.start.toIso8601String())
            .lte('created_at', dateRange.end.toIso8601String());
      }

      if (statusFilter != null) {
        query = query.eq('status', statusFilter.value);
      }

      if (ticketTypeFilter != null) {
        query = query.eq('ticket_type', ticketTypeFilter.value);
      }

      if (staffIdFilter != null) {
        query = query.eq('staff_id', staffIdFilter);
      }

      if (searchTerm != null && searchTerm.isNotEmpty) {
        // Filtra sui campi della tabella principale O su quelli della tabella joinata
        query = query.or('customer.name.ilike.%$searchTerm%');
      }

      final response = await query
          .order('created_at', ascending: false)
          .range(offset, offset + limit - 1);

      return (response as List).map((map) => TicketModel.fromMap(map)).toList();
    } catch (e) {
      throw Exception('$e');
    }
  }

  // --- RECUPERO PAGINATO CON FILTRI E JOIN DEI TICKET DI TUTTA L'AZIENDA ---
  Future<List<TicketModel>> fetchTickets({
    required String? companyId,
    String? storeId,
    required int offset,
    int limit = 50,
    String? searchTerm,
    DateTimeRange? dateRange,
    TicketStatus? ticketStatusFilter,
    TicketType? ticketTypeFilter,
    String? staffIdFilter,
  }) async {
    try {
      var query = _supabase
          .from(_tableName)
          .select('''
            *,
            customer:${Tables.customers}!ticket_customer_id_fkey (*),
            ${Tables.shippingDocuments} (*, ${Tables.attachments} (*)),
            created_by:${Tables.staffMembers}!ticket_staff_id_fkey (*),
            assigned_to:${Tables.staffMembers}!ticket_assigned_to_id_fkey (*),
            target_model:${Tables.models}!ticket_model_id_1_fkey (*),
            source_model:${Tables.models}!ticket_model_id_2_fkey (*)
          ''')
          .eq('company_id', companyId!);

      // Filtro Range Date
      if (dateRange != null) {
        query = query
            .gte('created_at', dateRange.start.toIso8601String())
            .lte('created_at', dateRange.end.toIso8601String());
      }

      if (storeId != null) {
        query = query.or('store_id.eq.$storeId,store_id.is.null');
      }

      if (ticketStatusFilter != null) {
        query = query.eq('status', ticketStatusFilter.value);
      }

      if (ticketTypeFilter != null) {
        query = query.eq('ticket_type', ticketTypeFilter.value);
      }

      if (staffIdFilter != null) {
        query = query.eq('staff_id', staffIdFilter);
      }

      if (searchTerm != null && searchTerm.isNotEmpty) {
        // Filtra sui campi della tabella principale O su quelli della tabella joinata
        query = query.or('customer.name.ilike.%$searchTerm%');
      }

      final response = await query
          .order('created_at', ascending: false)
          .range(offset, offset + limit - 1);

      return (response as List).map((map) => TicketModel.fromMap(map)).toList();
    } catch (e) {
      throw Exception('$e');
    }
  }

  /// Stream dei ticket che necessitano attenzione (es. in scadenza oggi o in ritardo)
  Stream<List<TicketModel>> getAttentionNeededTicketsStream() {
    return _supabase
        .from(_tableName)
        .stream(primaryKey: ['id'])
        .eq('store_id', GetIt.I.get<SessionCubit>().state.currentStore!.id!)
        // Purtroppo lo stream accetta solo filtri base, quindi ci facciamo
        // mandare i dati e li filtriamo con la potenza di Dart!
        .limit(300)
        .map((listOfMaps) {
          final now = DateTime.now();
          final endOfToday = DateTime(now.year, now.month, now.day, 23, 59, 59);

          // 1. Mappiamo tutto in TicketModel
          final allStoreTickets = listOfMaps
              .map((map) => TicketModel.fromMap(map))
              .toList();

          // 2. Filtriamo in memoria!
          final urgentTickets = allStoreTickets.where((ticket) {
            // Escludiamo quelli già chiusi o consegnati
            if (ticket.ticketStatus == TicketStatus.closed ||
                ticket.ticketStatus == TicketStatus.ready) {
              return false;
            }

            // Se c'è una data di consegna stimata ed è <= a stasera, è urgente!
            if (ticket.estimatedDeliveryAt != null) {
              return ticket.estimatedDeliveryAt!.isBefore(endOfToday);
            }

            return false;
          }).toList();

          // 3. Li ordiniamo mettendo i più vecchi/urgenti in cima
          urgentTickets.sort(
            (a, b) => a.estimatedDeliveryAt!.compareTo(b.estimatedDeliveryAt!),
          );

          return urgentTickets;
        });
  }

  Stream<List<TicketModel>> getLatestStoreTicketsStream({
    required String storeId,
    required int limit,
  }) {
    return _supabase
        .from(_tableName)
        .stream(primaryKey: ['id'])
        .eq('store_id', storeId)
        .order('created_at', ascending: false)
        .limit(limit)
        .map(
          (listOfMaps) =>
              listOfMaps.map((map) => TicketModel.fromMap(map)).toList(),
        );
  }

  /// Recupera un ticket specifico CON TUTTE LE RELAZIONI espanse (Cliente e Modelli)
  /// Questa è la vera magia di Supabase!
  Future<TicketModel> getTicketById(String ticketId) async {
    try {
      // Usiamo i nomi esatti delle Foreign Key che hai definito nell'SQL!
      final response = await _supabase
          .from(_tableName)
          .select('''
            *,
            customer:${Tables.customers}!ticket_customer_id_fkey (*),
            target_model:${Tables.models}!ticket_model_id_1_fkey (*),
            source_model:${Tables.models}!ticket_model_id_2_fkey (*),
            created_by:${Tables.staffMembers}!ticket_staff_id_fkey (*),
            assigned_to:${Tables.staffMembers}!ticket_assigned_to_id_fkey (*),
            ${Tables.shippingDocuments} (*, ${Tables.attachments} (*))
          ''')
          .eq('id', ticketId)
          .single();

      return TicketModel.fromMap(response);
    } catch (e) {
      throw Exception('Errore nel recupero del dettaglio ticket: $e');
    }
  }

  /// Salva il ticket
  Future<TicketModel> insertTicket(TicketModel ticket) async {
    if (ticket.id != null) {
      throw Exception('Impossibile creare un ticket esistente, id not null');
    }
    try {
      final ticketToSave = ticket.copyWith(
        referenceId: await _documentSequenceRepository.getNextDocumentNumber(
          DocumentType.ticket.name,
        ),
      );
      final response = await _supabase
          .from(_tableName)
          .insert(ticketToSave.toMap())
          .select()
          .single();

      return TicketModel.fromMap(response);
    } catch (e) {
      throw Exception('Errore nella creazione del ticket: $e');
    }
  }

  /// Aggiorna un ticket esistente
  Future<TicketModel> updateTicket(TicketModel ticket) async {
    if (ticket.id == null) {
      throw Exception('Impossibile aggiornare un ticket senza ID');
    }

    try {
      final response = await _supabase
          .from(_tableName)
          .update(ticket.toMap())
          .eq('id', ticket.id!)
          .select()
          .single();

      return TicketModel.fromMap(response);
    } catch (e) {
      throw Exception('Errore nell\'aggiornamento del ticket: $e');
    }
  }

  /// Chiude i ticket in bulk
  Future<void> closeTickets(List<String> ticketIds) async {
    try {
      await _supabase
          .from(_tableName)
          .update({'ticket_status': TicketStatus.closed.value})
          .inFilter('id', ticketIds);
    } catch (e) {
      throw Exception('Errore nella chiusura dei ticket: $e');
    }
  }

  /// Elimina (o annulla) un ticket
  Future<void> deleteTicket(String ticketId) async {
    try {
      await _supabase.from(_tableName).delete().eq('id', ticketId);
    } catch (e) {
      throw Exception('Errore nell\'eliminazione del ticket: $e');
    }
  }
}
