// SPDX-FileCopyrightText: © 2025 Nøkken.io <nokken.io@proton.me>
// SPDX-License-Identifier: AGPL-3.0
//
//  add_edit_medication_screen.dart
//  Screen that handles both adding new medications and editing existing ones
//  Uses a form with multiple sections for different medication properties
//
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:nokken/src/core/services/navigation/navigation_service.dart';
import 'package:nokken/src/core/ui/theme/app_icons.dart';
import 'package:nokken/src/core/ui/theme/app_theme.dart';
import 'package:nokken/src/core/ui/theme/app_colors.dart';
import 'package:nokken/src/core/ui/theme/app_text_styles.dart';
import 'package:nokken/src/features/medication_tracker/models/medication.dart';
import 'package:nokken/src/features/medication_tracker/providers/medication_state.dart';
import 'package:nokken/src/core/ui/widgets/dialog_service.dart';

import 'package:nokken/src/features/medication_tracker/screens/add_edit_medication/widgets/add_edit_widgets.dart';

class AddEditMedicationScreen extends ConsumerStatefulWidget {
  final Medication? medication;

  const AddEditMedicationScreen({
    super.key,
    this.medication,
  });

  @override
  ConsumerState<AddEditMedicationScreen> createState() =>
      _AddEditMedicationScreenState();
}

class _AddEditMedicationScreenState
    extends ConsumerState<AddEditMedicationScreen> {
  final _formKey = GlobalKey<FormState>();

  // Controllers that need disposal
  late final TextEditingController _nameController;
  late final TextEditingController _dosageController;
  late final TextEditingController _notesController;
  late final TextEditingController _doctorController;
  late final TextEditingController _pharmacyController;
  late bool _asNeeded;

  // State variables
  late MedicationType _medicationType;
  late OralSubtype? _oralSubtype;
  late TopicalSubtype? _topicalSubtype;
  late DateTime _startDate;
  late int _frequency;
  late List<TimeOfDay> _times;
  late Set<String> _selectedDays;
  late int _currentQuantity;
  late int _refillThreshold;
  late InjectionDetails? _injectionDetails;
  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    _initializeFields();
  }

  /// Initialize all form fields with either existing medication data or defaults
  void _initializeFields() {
    // Initialize controllers
    _nameController =
        TextEditingController(text: widget.medication?.name ?? '');
    _dosageController =
        TextEditingController(text: widget.medication?.dosage ?? '');
    _notesController =
        TextEditingController(text: widget.medication?.notes ?? '');
    _doctorController =
        TextEditingController(text: widget.medication?.doctor ?? '');
    _pharmacyController =
        TextEditingController(text: widget.medication?.pharmacy ?? '');

    // Initialize medication type and related fields
    _medicationType = widget.medication?.medicationType ?? MedicationType.oral;
    _oralSubtype = widget.medication?.oralSubtype ?? OralSubtype.tablets;
    _topicalSubtype = widget.medication?.topicalSubtype ?? TopicalSubtype.gel;
    _injectionDetails = _initializeInjectionDetails();

    // Initialize schedule related fields
    _startDate = widget.medication?.startDate ?? DateTime.now();
    _frequency = widget.medication?.frequency ?? 1;
    _times = _initializeTimes();
    _selectedDays = widget.medication?.daysOfWeek ??
        <String>{'Su', 'M', 'T', 'W', 'Th', 'F', 'Sa'};

    // Initialize as-needed flag
    _asNeeded = widget.medication?.asNeeded ?? false;

    // Initialize inventory related fields
    _currentQuantity = widget.medication?.currentQuantity ?? 0;
    _refillThreshold = widget.medication?.refillThreshold ?? 0;
  }

  /// Initialize time slots from existing medication or default to current time
  List<TimeOfDay> _initializeTimes() {
    if (widget.medication != null) {
      return widget.medication!.timeOfDay
          .map((dt) => TimeOfDay.fromDateTime(dt))
          .toList();
    }
    return [TimeOfDay.now()];
  }

  /// Initialize injection details if applicable
  InjectionDetails? _initializeInjectionDetails() {
    if (_medicationType == MedicationType.injection) {
      return widget.medication?.injectionDetails ??
          InjectionDetails(
            drawingNeedleType: '',
            drawingNeedleCount: 0,
            drawingNeedleRefills: 0,
            injectingNeedleType: '',
            injectingNeedleCount: 0,
            injectingNeedleRefills: 0,
            syringeType: '',
            syringeCount: 0,
            syringeRefills: 0,
            injectionSiteNotes: '',
            frequency: InjectionFrequency.weekly,
            subtype: InjectionSubtype.intramuscular,
          );
    }
    return null;
  }

  void _handleAsNeededToggle(bool value) {
    setState(() {
      _asNeeded = value;

      // If switching to scheduled mode, ensure we have enough time slots
      if (!value && (_times.isEmpty || _times.length != _frequency)) {
        // Initialize with correct number of time slots
        _times = List.generate(
          _frequency,
          (_) => TimeOfDay.now(),
        );
      }
    });
  }

  /// Handle medication type change (oral/injection/topical/patch)
  void _handleTypeChange(MedicationType type) {
    setState(() {
      _medicationType = type;

      // Reset subtypes based on selected type
      if (type == MedicationType.oral) {
        _oralSubtype = OralSubtype.tablets;
        _topicalSubtype = null;
        _injectionDetails = null;
        _frequency = 1;
        _selectedDays = {'Su', 'M', 'T', 'W', 'Th', 'F', 'Sa'};
      } else if (type == MedicationType.injection) {
        _oralSubtype = null;
        _topicalSubtype = null;
        _frequency = 1;
        _selectedDays = {'Su'};
        _injectionDetails ??= _initializeInjectionDetails();
      } else if (type == MedicationType.topical) {
        _oralSubtype = null;
        _topicalSubtype = TopicalSubtype.gel;
        _injectionDetails = null;
        _frequency = 1;
        _selectedDays = {'Su', 'M', 'T', 'W', 'Th', 'F', 'Sa'};
      } else if (type == MedicationType.patch) {
        _oralSubtype = null;
        _topicalSubtype = null;
        _injectionDetails = null;
        _frequency = 1;
        _selectedDays = {'Su', 'M', 'T', 'W', 'Th', 'F', 'Sa'};
      }
    });
  }

  // Clean up controllers to prevent memory leaks
  @override
  void dispose() {
    _nameController.dispose();
    _dosageController.dispose();
    _notesController.dispose();
    _doctorController.dispose();
    _pharmacyController.dispose();
    super.dispose();
  }

  /// Update injection details when fields change
  void _updateInjectionDetails({
    String? drawingNeedleType,
    int? drawingNeedleCount,
    int? drawingNeedleRefills,
    String? injectingNeedleType,
    int? injectingNeedleCount,
    int? injectingNeedleRefills,
    String? syringeType,
    int? syringeCount,
    int? syringeRefills,
    String? injectionSiteNotes,
    InjectionFrequency? frequency,
    InjectionSubtype? subtype,
    InjectionSiteRotation? siteRotation, // Added parameter
  }) {
    if (_injectionDetails == null) return;

    setState(() {
      _injectionDetails = InjectionDetails(
        drawingNeedleType:
            drawingNeedleType ?? _injectionDetails!.drawingNeedleType,
        drawingNeedleCount:
            drawingNeedleCount ?? _injectionDetails!.drawingNeedleCount,
        drawingNeedleRefills:
            drawingNeedleRefills ?? _injectionDetails!.drawingNeedleRefills,
        injectingNeedleType:
            injectingNeedleType ?? _injectionDetails!.injectingNeedleType,
        injectingNeedleCount:
            injectingNeedleCount ?? _injectionDetails!.injectingNeedleCount,
        injectingNeedleRefills:
            injectingNeedleRefills ?? _injectionDetails!.injectingNeedleRefills,
        syringeType: syringeType ?? _injectionDetails!.syringeType,
        syringeCount: syringeCount ?? _injectionDetails!.syringeCount,
        syringeRefills: syringeRefills ?? _injectionDetails!.syringeRefills,
        injectionSiteNotes:
            injectionSiteNotes ?? _injectionDetails!.injectionSiteNotes,
        frequency: frequency ?? _injectionDetails!.frequency,
        subtype: subtype ?? _injectionDetails!.subtype,
        siteRotation:
            siteRotation ?? _injectionDetails!.siteRotation, // Added field
      );
    });

    // Ensure frequency is 1 when biweekly is selected
    if (frequency == InjectionFrequency.biweekly && _frequency != 1) {
      _frequency = 1;
      _times = _adjustTimesList(_times, 1);
    }
  }

  /// Handle frequency change (times per day)
  void _handleFrequencyChange(int newFrequency) {
    setState(() {
      _frequency = newFrequency;

      // Always ensure _times list has exactly newFrequency entries
      _times = _adjustTimesList(_times, newFrequency);

      // If we're in as-needed mode, no need to show multiple time slots
      if (_asNeeded && newFrequency > 1) {
        _frequency = 1;
        _times = _times.sublist(0, 1);
      }
    });
  }

  /// Adjust the time slots list when frequency changes
  List<TimeOfDay> _adjustTimesList(
      List<TimeOfDay> currentTimes, int newFrequency) {
    if (newFrequency > currentTimes.length) {
      // Add new time slots if frequency increases
      return [
        ...currentTimes,
        ...List.generate(
          newFrequency - currentTimes.length,
          (_) => TimeOfDay.now(),
        )
      ];
    }
    // Remove excess time slots if frequency decreases
    return currentTimes.sublist(0, newFrequency);
  }

  /// Handle changes to individual time slots
  void _handleTimeChange(int index, TimeOfDay newTime) {
    setState(() {
      // Make sure index is valid
      if (index >= 0 && index < _times.length) {
        _times[index] = newTime;
      }
    });
  }

  /// Handle changes to the selected days of the week
  void _handleDaysChange(Set<String> newDays) {
    setState(() {
      _selectedDays = newDays;
    });
  }

  /// Save or update medication data
  Future<void> _saveMedication() async {
    // Validate form before proceeding
    if (!_formKey.currentState!.validate()) return;

    // Show loading indicator
    setState(() => _isLoading = true);

    try {
      // Initialize timeOfDay list based on medication type
      List<DateTime> timeOfDay = [];

      if (_asNeeded) {
        // For as-needed medications, ensure we have at least one default time
        final now = DateTime.now();
        timeOfDay = [
          DateTime(now.year, now.month, now.day, now.hour, now.minute)
        ];
      } else {
        // For scheduled medications, convert all _times entries to DateTime objects
        timeOfDay = _times.map((time) {
          final now = DateTime.now();
          return DateTime(
            now.year,
            now.month,
            now.day,
            time.hour,
            time.minute,
          );
        }).toList();

        // Double-check that we have the correct number of time entries
        if (timeOfDay.length != _frequency) {
          throw MedicationException('Number of times must match frequency');
        }
      }

      // Create medication object from form data
      final medication = Medication(
        id: widget.medication?.id, // null for new, existing id for updates
        name: _nameController.text.trim(),
        dosage: _dosageController.text.trim(),
        startDate: _startDate,
        frequency: _frequency,
        timeOfDay: timeOfDay,
        daysOfWeek: _selectedDays,
        currentQuantity: _currentQuantity,
        refillThreshold: _refillThreshold,
        notes: _notesController.text.trim().isNotEmpty
            ? _notesController.text.trim()
            : null,
        medicationType: _medicationType,
        oralSubtype:
            _medicationType == MedicationType.oral ? _oralSubtype : null,
        topicalSubtype:
            _medicationType == MedicationType.topical ? _topicalSubtype : null,
        doctor: _doctorController.text.trim().isNotEmpty
            ? _doctorController.text.trim()
            : null,
        pharmacy: _pharmacyController.text.trim().isNotEmpty
            ? _pharmacyController.text.trim()
            : null,
        injectionDetails: _injectionDetails,
        asNeeded: _asNeeded,
      );

      // If medication is null, we're adding new
      // Otherwise, we're updating existing
      if (widget.medication == null) {
        await ref
            .read(medicationStateProvider.notifier)
            .addMedication(medication);
      } else {
        await ref
            .read(medicationStateProvider.notifier)
            .updateMedication(medication);
      }

      // Return to details screen
      if (mounted) {
        NavigationService.goToMedicationDetails(context,
            medication: medication);
      }
    } catch (e) {
      // Show error in snackbar if something goes wrong
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(
            content: Text('Error: $e'),
            backgroundColor: AppColors.error,
          ),
        );
      }
    } finally {
      if (mounted) {
        setState(() => _isLoading = false);
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // Show different title based on add/edit mode
        title: Text(
            widget.medication == null ? 'Add Medication' : 'Edit Medication'),
        leading: IconButton(
          icon: Icon(AppIcons.getIcon('arrow_back')),
          onPressed: () => _handleBackButton(context, ref),
        ),
        actions: [
          // Show loading indicator or save button
          _isLoading
              ? const Center(
                  child: Padding(
                    padding: AppTheme.standardCardPadding,
                    child: CircularProgressIndicator(),
                  ),
                )
              : TextButton(
                  onPressed: _saveMedication,
                  child: Text(
                    'Save',
                    style: AppTextStyles.titleMedium,
                  ),
                ),
        ],
      ),
      // Main form layout using ListView for scrolling
      body: Form(
        key: _formKey,
        child: ListView(
          padding: AppTheme.standardCardPadding,
          children: [
            // Basic information section (name, dosage, inventory)
            BasicInfoSection(
              nameController: _nameController,
              dosageController: _dosageController,
              currentQuantity: _currentQuantity,
              refillThreshold: _refillThreshold,
              onQuantityChanged: (value) =>
                  setState(() => _currentQuantity = value),
              onThresholdChanged: (value) =>
                  setState(() => _refillThreshold = value),
            ),

            // Medication type section
            MedicationTypeSection(
              medicationType: _medicationType,
              onTypeChanged: _handleTypeChange,
            ),

            // Oral subtype section (only shown for oral medications)
            if (_medicationType == MedicationType.oral)
              OralSubtypeSection(
                subtype: _oralSubtype,
                onSubtypeChanged: (value) =>
                    setState(() => _oralSubtype = value),
              ),

            // Topical subtype section (only shown for topical medications)
            if (_medicationType == MedicationType.topical)
              TopicalSubtypeSection(
                subtype: _topicalSubtype,
                onSubtypeChanged: (value) =>
                    setState(() => _topicalSubtype = value),
              ),

            // Injection details section (only shown for injectable medications)
            if (_medicationType == MedicationType.injection)
              InjectionDetailsSection(
                injectionDetails: _injectionDetails!,
                onDetailsChanged: _updateInjectionDetails,
              ),

            // Timing section
            TimingSection(
              selectedStartDate: _startDate,
              onStartDateChanged: (date) => setState(() => _startDate = date),
              frequency: _frequency,
              times: _times,
              selectedDays: _selectedDays,
              onFrequencyChanged: _handleFrequencyChange,
              onTimeChanged: _handleTimeChange,
              onDaysChanged: _handleDaysChange,
              isEveryTwoWeeks: _medicationType == MedicationType.injection &&
                  _injectionDetails?.frequency == InjectionFrequency.biweekly,
              medicationType: _medicationType,
              asNeeded: _asNeeded,
              onAsNeededChanged: _handleAsNeededToggle,
            ),

            // Medical providers section
            MedicalProvidersSection(
              doctorController: _doctorController,
              pharmacyController: _pharmacyController,
            ),

            // Notes section
            NotesSection(controller: _notesController),

            Row(
              children: [
                // Delete button on left (only if medication exists)
                if (widget.medication != null)
                  SizedBox(
                    height: 36,
                    child: ElevatedButton.icon(
                      icon: Icon(
                        AppIcons.getIcon('delete'),
                        size: 18,
                        color: AppColors.error,
                      ),
                      label: Text('Delete'),
                      style: ElevatedButton.styleFrom(
                        backgroundColor: AppColors.error.withAlpha(40),
                        foregroundColor: AppColors.error,
                        padding: const EdgeInsets.symmetric(
                            horizontal: 12, vertical: 0),
                        minimumSize: Size.zero,
                        tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                      ),
                      onPressed: () => _showDeleteDialog(context, ref),
                    ),
                  ),

                // Push save button to the right
                const Spacer(),

                // Save button on right
                SizedBox(
                  height: 36,
                  child: ElevatedButton.icon(
                    icon: Icon(
                      AppIcons.getIcon('save'),
                      size: 18,
                      color: AppColors.primary,
                    ),
                    label: Text('Save'),
                    style: ElevatedButton.styleFrom(
                      backgroundColor: AppColors.primary.withAlpha(40),
                      foregroundColor: AppColors.primary,
                      padding: const EdgeInsets.symmetric(
                          horizontal: 12, vertical: 0),
                      minimumSize: Size.zero,
                      tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                    ),
                    onPressed: () => _saveMedication(),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }

  bool _checkForUnsavedChanges() {
    // For new entries, if any field has content, there are unsaved changes
    if (widget.medication == null) {
      // Check if any required field has been filled
      if (_nameController.text.isNotEmpty ||
          _dosageController.text.isNotEmpty ||
          _notesController.text.isNotEmpty ||
          _doctorController.text.isNotEmpty ||
          _pharmacyController.text.isNotEmpty) {
        return true;
      }

      // Check if any other field has been modified from default values
      if (_medicationType != MedicationType.oral ||
          _oralSubtype != OralSubtype.tablets ||
          _currentQuantity != 0 ||
          _refillThreshold != 0) {
        return true;
      }

      // Check if date was modified from the default (today)
      final now = DateTime.now();
      final today = DateTime(now.year, now.month, now.day);
      final selectedDate =
          DateTime(_startDate.year, _startDate.month, _startDate.day);
      if (selectedDate != today) {
        return true;
      }

      return false;
    }

    // For existing entries, compare with original values
    else {
      // Compare basic text fields
      if (_nameController.text != widget.medication!.name ||
          _dosageController.text != widget.medication!.dosage ||
          _notesController.text != (widget.medication!.notes ?? '') ||
          _doctorController.text != (widget.medication!.doctor ?? '') ||
          _pharmacyController.text != (widget.medication!.pharmacy ?? '')) {
        return true;
      }

      // Compare medication type and related fields
      if (_medicationType != widget.medication!.medicationType) {
        return true;
      }

      // Compare type-specific fields
      if (_medicationType == MedicationType.oral &&
          _oralSubtype != widget.medication!.oralSubtype) {
        return true;
      }

      if (_medicationType == MedicationType.topical &&
          _topicalSubtype != widget.medication!.topicalSubtype) {
        return true;
      }

      // Compare injection details if applicable
      if (_medicationType == MedicationType.injection) {
        final origDetails = widget.medication!.injectionDetails;
        final currDetails = _injectionDetails;

        if ((origDetails == null && currDetails != null) ||
            (origDetails != null && currDetails == null)) {
          return true;
        }

        if (origDetails != null && currDetails != null) {
          if (origDetails.frequency != currDetails.frequency ||
              origDetails.subtype != currDetails.subtype ||
              origDetails.drawingNeedleType != currDetails.drawingNeedleType ||
              origDetails.drawingNeedleCount !=
                  currDetails.drawingNeedleCount ||
              origDetails.drawingNeedleRefills !=
                  currDetails.drawingNeedleRefills ||
              origDetails.injectingNeedleType !=
                  currDetails.injectingNeedleType ||
              origDetails.injectingNeedleCount !=
                  currDetails.injectingNeedleCount ||
              origDetails.injectingNeedleRefills !=
                  currDetails.injectingNeedleRefills ||
              origDetails.syringeType != currDetails.syringeType ||
              origDetails.syringeCount != currDetails.syringeCount ||
              origDetails.syringeRefills != currDetails.syringeRefills ||
              origDetails.injectionSiteNotes !=
                  currDetails.injectionSiteNotes) {
            return true;
          }

          // Check site rotation if exists
          if ((origDetails.siteRotation == null &&
                  currDetails.siteRotation != null) ||
              (origDetails.siteRotation != null &&
                  currDetails.siteRotation == null)) {
            return true;
          }
        }
      }

      // Compare date
      final originalDate = widget.medication!.startDate;
      final originalDay =
          DateTime(originalDate.year, originalDate.month, originalDate.day);
      final currentDay =
          DateTime(_startDate.year, _startDate.month, _startDate.day);

      if (originalDay != currentDay) {
        return true;
      }

      // Compare frequency
      if (_frequency != widget.medication!.frequency) {
        return true;
      }

      // Compare times of day
      if (_times.length != widget.medication!.timeOfDay.length) {
        return true;
      }

      for (int i = 0; i < _times.length; i++) {
        final currTime = _times[i];
        final origTime =
            TimeOfDay.fromDateTime(widget.medication!.timeOfDay[i]);

        if (currTime.hour != origTime.hour ||
            currTime.minute != origTime.minute) {
          return true;
        }
      }

      // Compare days of week
      if (_selectedDays.length != widget.medication!.daysOfWeek.length) {
        return true;
      }

      for (final day in _selectedDays) {
        if (!widget.medication!.daysOfWeek.contains(day)) {
          return true;
        }
      }

      // Compare inventory values
      if (_currentQuantity != widget.medication!.currentQuantity ||
          _refillThreshold != widget.medication!.refillThreshold) {
        return true;
      }

      return false; // No changes detected
    }
  }

  void _handleBackButton(BuildContext context, WidgetRef ref) {
    DialogService.handleBackWithUnsavedChanges(
      context: context,
      ref: ref,
      checkForUnsavedChanges: _checkForUnsavedChanges,
      saveFn: _saveMedication,
    );
  }

  /// Show confirmation dialog before deleting medication
  Future<void> _showDeleteDialog(BuildContext context, WidgetRef ref) async {
    await DialogService.showDeleteDialog(
      context: context,
      ref: ref,
      itemName: _nameController.text.trim(),
      onDelete: () async {
        await ref
            .read(medicationStateProvider.notifier)
            .deleteMedication(widget.medication!.id);

        if (context.mounted) {
          NavigationService.goHome(context);
        }
      },
    );
  }
}
