import 'dart:async';

import 'package:flutter/foundation.dart';
import 'package:flux/core/enums_and_consts/consts.dart';
import 'package:flux/features/tasks/models/task_reminder_config.dart';
import 'package:flux/features/tasks/models/task_status.dart';
import 'package:get_it/get_it.dart';
import 'package:supabase_flutter/supabase_flutter.dart';
// Sostituisci con i percorsi corretti di FLUX
import 'package:flux/features/tasks/models/task_model.dart';

class TasksRepository {
  final _supabase = GetIt.I.get<SupabaseClient>();

  // =========================================================================
  // LETTURA REMINDER (Per il form in edit)
  // =========================================================================
  Future<List<TaskReminderConfig>> fetchPersonalReminders({
    required String taskId,
    required String staffId,
  }) async {
    try {
      final response = await _supabase
          .from('task_reminders')
          .select()
          .eq('task_id', taskId)
          .eq('staff_id', staffId)
          .eq(
            'is_forced',
            false,
          ); // Peschiamo SOLO quelli modificabili dall'utente

      return (response as List)
          .map(
            (r) => TaskReminderConfig(
              minutesBefore: r['minutes_before'],
              channel: r['channel'],
            ),
          )
          .toList();
    } catch (e) {
      debugPrint('Errore fetch personal reminders: $e');
      throw Exception('Errore fetch personal reminders: $e');
    }
  }

  // --- RECUPERO DEI TASK FILTRATI ---
  Future<List<TaskModel>> getTasks({
    required String companyId,
    String? storeId,
    String? staffId,
    List<TaskStatus>? statuses,
    int? limit,
  }) async {
    try {
      // 1. FASE FILTRI: Usa il join esplicito stile "Notes"
      var filterBuilder = _supabase
          .from(Tables.tasks)
          .select('''
            *,
            task_assignments:${Tables.taskAssignments} (
              ${Tables.staffMembers} (*)
            )
          ''')
          .eq('company_id', companyId);

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

      if (staffId != null) {
        // Grazie al trigger, hai l'array pronto per il filtro senza impazzire!
        filterBuilder = filterBuilder.contains('assigned_to_ids', [staffId]);
      }

      if (statuses != null && statuses.isNotEmpty) {
        final statusValues = statuses.map((s) => s.toValue).toList();
        filterBuilder = filterBuilder.inFilter('status', statusValues);
      }

      // 2. FASE TRASFORMAZIONI
      var transformBuilder = filterBuilder
          .order('due_date', ascending: true, nullsFirst: false)
          .order('created_at', ascending: false, nullsFirst: false);

      if (limit != null) {
        transformBuilder = transformBuilder.limit(limit);
      }

      // 3. ESECUZIONE DELLA QUERY
      final response = await transformBuilder;

      // 4. PARSING DEI DATI
      return (response as List).map((json) => TaskModel.fromMap(json)).toList();
    } catch (e) {
      throw Exception('Errore nel recupero dei task: $e');
    }
  }

  Future<TaskModel?> fetchTaskById(String taskId) async {
    try {
      final response = await _supabase
          .from(Tables.tasks)
          .select('''
            *,
            task_assignments:${Tables.taskAssignments} (
              ${Tables.staffMembers} (*)
            )
          ''')
          .eq('id', taskId)
          .single();

      return TaskModel.fromMap(response);
    } catch (e) {
      debugPrint('Errore fetch task by id: $e');
      throw Exception('Errore fetch task by id: $e');
    }
  }

  // =========================================================================
  // REALTIME STREAM (La sentinella per la bacheca)
  // =========================================================================
  Stream<List<TaskModel>> watchCompanyTasks(String companyId) {
    return _supabase
        .from('tasks')
        .stream(primaryKey: ['id'])
        .eq('company_id', companyId)
        .map((listOfMaps) {
          return listOfMaps.map((map) => TaskModel.fromMap(map)).toList();
        });
  }

  // =========================================================================
  // CREAZIONE (Insert)
  // =========================================================================
  Future<void> createTask({
    required TaskModel task,
    required List<String> assignedStaffIds,
    required String currentUserId,
    required List<TaskReminderConfig> currentUserCustomReminders,
    TaskReminderConfig? managerForcedOverride,
  }) async {
    try {
      // 1. Inseriamo il Task principale per farci generare l'ID dal DB
      final taskResponse = await _supabase
          .from('tasks')
          .insert(task.toMap()) // Assicurati che toMap() escluda l'id se è null
          .select('id')
          .single();

      final String taskId = taskResponse['id'];

      // 2. Inseriamo le Assegnazioni (tabella task_assignments)
      if (assignedStaffIds.isNotEmpty) {
        final assignmentsToInsert = assignedStaffIds
            .map(
              (staffId) => {
                'task_id': taskId,
                'staff_id': staffId,
                'company_id': task.companyId,
              },
            )
            .toList();
        await _supabase.from('task_assignments').insert(assignmentsToInsert);
      }

      // Se non c'è data di scadenza, niente promemoria a tempo
      if (task.dueDate == null || assignedStaffIds.isEmpty) return;

      // 3. Setup Reminder: Peschiamo i default degli ALTRI dipendenti coinvolti
      final otherStaffIds = assignedStaffIds
          .where((id) => id != currentUserId)
          .toList();
      List<dynamic> otherDefaults = [];
      if (otherStaffIds.isNotEmpty) {
        otherDefaults = await _supabase
            .from('staff_task_reminder_defaults')
            .select()
            .inFilter('staff_id', otherStaffIds);
      }

      // 4. Creiamo la lista Bulk Insert per la tabella task_reminders
      List<Map<String, dynamic>> remindersToInsert = [];

      for (var staffId in assignedStaffIds) {
        // A) Se è l'utente loggato -> usa i reminder configurati nel form
        if (staffId == currentUserId) {
          for (var config in currentUserCustomReminders) {
            final triggerAt = task.dueDate!.subtract(
              Duration(minutes: config.minutesBefore),
            );
            if (triggerAt.isAfter(DateTime.now())) {
              remindersToInsert.add(
                _buildReminderRow(
                  task,
                  taskId,
                  staffId,
                  config,
                  triggerAt,
                  false,
                ),
              );
            }
          }
        }
        // B) Se è un collega -> eredita i suoi default preimpostati
        else {
          final staffRules = otherDefaults.where(
            (row) => row['staff_id'] == staffId,
          );
          for (var rule in staffRules) {
            final config = TaskReminderConfig(
              minutesBefore: rule['minutes_before'],
              channel: rule['channel'],
            );
            final triggerAt = task.dueDate!.subtract(
              Duration(minutes: config.minutesBefore),
            );
            if (triggerAt.isAfter(DateTime.now())) {
              remindersToInsert.add(
                _buildReminderRow(
                  task,
                  taskId,
                  staffId,
                  config,
                  triggerAt,
                  false,
                ),
              );
            }
          }
        }

        // C) Override forzato del manager (per tutti)
        if (managerForcedOverride != null) {
          final triggerAt = task.dueDate!.subtract(
            Duration(minutes: managerForcedOverride.minutesBefore),
          );
          if (triggerAt.isAfter(DateTime.now())) {
            remindersToInsert.add(
              _buildReminderRow(
                task,
                taskId,
                staffId,
                managerForcedOverride,
                triggerAt,
                true,
              ),
            );
          }
        }
      }

      // 5. Inserimento massivo finale
      if (remindersToInsert.isNotEmpty) {
        await _supabase.from('task_reminders').insert(remindersToInsert);
      }
    } catch (e) {
      throw Exception('Errore durante la creazione del task: $e');
    }
  }

  // =========================================================================
  // AGGIORNAMENTO (Update)
  // =========================================================================
  Future<void> updateTask({
    required TaskModel task,
    required List<String> assignedStaffIds,
    required String currentUserId,
    required List<TaskReminderConfig> currentUserCustomReminders,
  }) async {
    try {
      final taskId = task.id!;

      // 1. Aggiornamento dati Task Base
      await _supabase
          .from('tasks')
          .update({
            'title': task.title,
            'description': task.description,
            'due_date': task.dueDate?.toIso8601String(),
            'store_id': task.storeId,
            'updated_at': DateTime.now().toIso8601String(),
          })
          .eq('id', taskId);

      // 2. Aggiornamento Assegnazioni: eliminiamo le vecchie, inseriamo le nuove
      await _supabase.from('task_assignments').delete().eq('task_id', taskId);
      if (assignedStaffIds.isNotEmpty) {
        final assignmentsToInsert = assignedStaffIds
            .map(
              (staffId) => {
                'task_id': taskId,
                'staff_id': staffId,
                'company_id': task.companyId,
              },
            )
            .toList();
        await _supabase.from('task_assignments').insert(assignmentsToInsert);
      }

      // Se non c'è una data, eliminiamo tutti i vecchi promemoria dell'utente loggato per pulizia
      if (task.dueDate == null) {
        await _supabase
            .from('task_reminders')
            .delete()
            .eq('task_id', taskId)
            .eq('staff_id', currentUserId)
            .eq('is_forced', false);
        return;
      }

      // 3. GESTIONE REMINDER: Puliamo SOLO quelli modificabili dall'utente loggato
      await _supabase
          .from('task_reminders')
          .delete()
          .eq('task_id', taskId)
          .eq('staff_id', currentUserId)
          .eq('is_forced', false); // NON tocchiamo quelli forzati dal manager!

      // 4. Inseriamo le nuove configurazioni salvate dal Cubit (solo se è ancora tra gli assegnatari)
      if (assignedStaffIds.contains(currentUserId) &&
          currentUserCustomReminders.isNotEmpty) {
        final List<Map<String, dynamic>> toInsert = [];

        for (var config in currentUserCustomReminders) {
          final triggerAt = task.dueDate!.subtract(
            Duration(minutes: config.minutesBefore),
          );
          if (triggerAt.isAfter(DateTime.now())) {
            toInsert.add(
              _buildReminderRow(
                task,
                taskId,
                currentUserId,
                config,
                triggerAt,
                false,
              ),
            );
          }
        }

        if (toInsert.isNotEmpty) {
          await _supabase.from('task_reminders').insert(toInsert);
        }
      }
    } catch (e) {
      throw Exception('Errore durante l\'aggiornamento del task: $e');
    }
  }

  // --- HELPER PRIVATO PER LA MAPPA DEL REMINDER ---
  Map<String, dynamic> _buildReminderRow(
    TaskModel task,
    String taskId,
    String staffId,
    TaskReminderConfig config,
    DateTime triggerAt,
    bool isForced,
  ) {
    return {
      'company_id': task.companyId,
      'task_id': taskId,
      'staff_id': staffId,
      'minutes_before': config.minutesBefore,
      'channel': config.channel,
      'trigger_at': triggerAt.toIso8601String(),
      'is_forced': isForced,
      'is_sent': false,
    };
  }
}
