import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:my_attendance/models/attendance_entry.dart';
import 'package:my_attendance/utils/database_helper.dart';

class AttendanceService with ChangeNotifier {
  final DatabaseHelper _dbHelper = DatabaseHelper();

  AttendanceEntry? _todayEntry;
  AttendanceEntry? get todayEntry => _todayEntry;

  List<AttendanceEntry> _history = [];
  List<AttendanceEntry> get history => _history;

  Map<String, int> _monthlyStats = {};
  Map<String, int> get monthlyStats => _monthlyStats;

  Map<String, int> _yearlyStats = {};
  Map<String, int> get yearlyStats => _yearlyStats;

  bool _isLoading = true;
  bool get isLoading => _isLoading;

  AttendanceService() {
    loadTodayEntry();
  }

  Future<void> logIn() async {
    _isLoading = true;
    notifyListeners();
    try {
      final now = DateTime.now();
      final date = DateTime(now.year, now.month, now.day);

      final entry = AttendanceEntry(
        date: date,
        loginTime: now,
        entryType: EntryType.work,
      );

      final id = await _dbHelper.insertAttendance(entry);
      _todayEntry = entry.copyWith(id: id);
    } catch (e) {
      debugPrint("Error logging in: $e");
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> logOut() async {
    if (_todayEntry == null || _todayEntry!.logoutTime != null) return;

    _isLoading = true;
    notifyListeners();
    try {
      final now = DateTime.now();
      final updatedEntry = _todayEntry!.copyWith(logoutTime: now);
      await _dbHelper.updateAttendance(updatedEntry);
      _todayEntry = updatedEntry;
    } catch (e) {
      debugPrint("Error logging out: $e");
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadTodayEntry() async {
    _isLoading = true;
    notifyListeners();
    try {
      final now = DateTime.now();
      final date = DateTime(now.year, now.month, now.day);
      _todayEntry = await _dbHelper.getAttendanceForDate(date);
    } catch (e) {
      debugPrint("Error loading today's entry: $e");
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> loadHistory({int limit = 10}) async {
    _isLoading = true;
    notifyListeners();
    try {
      _history = await _dbHelper.getAttendanceHistory(limit: limit);
    } catch (e) {
      debugPrint("Error loading history: $e");
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> updateNotes(int entryId, String notes) async {
    try {
      AttendanceEntry? entryToUpdate;
      if (_todayEntry?.id == entryId) {
        entryToUpdate = _todayEntry;
      } else {
        entryToUpdate = _history.firstWhere((e) => e.id == entryId);
      }

      if (entryToUpdate != null) {
        final updated = entryToUpdate.copyWith(notes: notes);
        await _dbHelper.updateAttendance(updated);
        await loadTodayEntry();
        await loadHistory();
        await calculateStats();
      }
    } catch (e) {
      debugPrint("Error updating notes: $e");
    }
  }

  Future<void> markAsWfh() async {
    _isLoading = true;
    notifyListeners();
    try {
      final now = DateTime.now();
      final date = DateTime(now.year, now.month, now.day);
      final entry = AttendanceEntry(date: date, entryType: EntryType.wfh);
      final id = await _dbHelper.insertAttendance(entry);
      _todayEntry = entry.copyWith(id: id);
      await calculateStats();
    } catch (e) {
      debugPrint("Error marking as WFH: $e");
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> markAsLeave(LeaveType leaveType) async {
    _isLoading = true;
    notifyListeners();
    try {
      final now = DateTime.now();
      final date = DateTime(now.year, now.month, now.day);
      final entry = AttendanceEntry(
        date: date,
        entryType: EntryType.leave,
        leaveType: leaveType,
      );
      final id = await _dbHelper.insertAttendance(entry);
      _todayEntry = entry.copyWith(id: id);
      await calculateStats();
    } catch (e) {
      debugPrint("Error marking as leave: $e");
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> resetData() async {
    _isLoading = true;
    notifyListeners();
    try {
      await _dbHelper.resetDatabase();
      _todayEntry = null;
      _history = [];
      await calculateStats();
    } catch (e) {
      debugPrint("Error resetting data: $e");
    } finally {
      _isLoading = false;
      notifyListeners();
    }
  }

  Future<void> updateOrCreateEntry(AttendanceEntry entry) async {
    final existingEntry = await _dbHelper.getAttendanceForDate(entry.date);
    if (existingEntry != null) {
      // Preserve the original ID when updating
      await _dbHelper.updateAttendance(entry.copyWith(id: existingEntry.id));
    } else {
      await _dbHelper.insertAttendance(entry);
    }
    // Refresh data to reflect changes
    await loadTodayEntry();
    await loadHistory();
    await calculateStats();
  }

  Future<AttendanceEntry?> getEntryForDate(DateTime date) async {
    return await _dbHelper.getAttendanceForDate(date);
  }

  Future<void> calculateStats() async {
    final now = DateTime.now();

    // Monthly stats
    final monthStart = DateTime(now.year, now.month, 1);
    final monthEnd = DateTime(now.year, now.month + 1, 0);
    final monthlyEntries = await _dbHelper.getAttendanceInRange(
      monthStart,
      monthEnd,
    );
    _monthlyStats = _calculateCounts(monthlyEntries);

    // Yearly stats
    final yearStart = DateTime(now.year, 1, 1);
    final yearEnd = DateTime(now.year, 12, 31);
    final yearlyEntries = await _dbHelper.getAttendanceInRange(
      yearStart,
      yearEnd,
    );
    _yearlyStats = _calculateCounts(yearlyEntries);

    notifyListeners();
  }

  Map<String, int> _calculateCounts(List<AttendanceEntry> entries) {
    final counts = <String, int>{};
    for (final entry in entries) {
      if (entry.entryType == EntryType.wfh) {
        counts['Work From Home'] = (counts['Work From Home'] ?? 0) + 1;
      } else if (entry.entryType == EntryType.leave) {
        final leaveName = _getLeaveTypeName(entry.leaveType);
        counts[leaveName] = (counts[leaveName] ?? 0) + 1;
      }
    }
    return counts;
  }

  String _getLeaveTypeName(LeaveType? type) {
    switch (type) {
      case LeaveType.sick:
        return 'Sick Leave';
      case LeaveType.annual:
        return 'Annual Leave';
      case LeaveType.nationalHoliday:
        return 'National Holiday';
      case LeaveType.companyWfh:
        return 'Company WFH';
      default:
        return 'On Leave';
    }
  }
}
