import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:hmg_patient_app_new/core/app_state.dart';
import 'package:hmg_patient_app_new/features/profile_settings/profile_settings_view_model.dart';

/// ViewModel for managing profile picture state and operations
/// Handles caching, loading, uploading, and user switching scenarios
class ProfilePictureViewModel extends ChangeNotifier {
  final AppState _appState;
  final ProfileSettingsViewModel _profileSettingsViewModel;

  ProfilePictureViewModel({
    required AppState appState,
    required ProfileSettingsViewModel profileSettingsViewModel,
  })  : _appState = appState,
        _profileSettingsViewModel = profileSettingsViewModel;

  // State variables
  File? _selectedImage;
  int? _currentPatientId;
  bool _isInitialLoadTriggered = false;

  /// Cache decoded image bytes to avoid decoding base64 on every rebuild
  Uint8List? _cachedImageBytes;
  String? _cachedImageDataHash;

  /// ValueNotifier for targeted profile image updates (prevents full screen rebuild)
  final ValueNotifier<int> _profileImageVersion = ValueNotifier<int>(0);

  // Getters
  File? get selectedImage => _selectedImage;

  Uint8List? get cachedImageBytes => _cachedImageBytes;

  bool get isInitialLoadTriggered => _isInitialLoadTriggered;

  int? get currentPatientId => _currentPatientId;

  ValueNotifier<int> get profileImageVersion => _profileImageVersion;

  /// Initialize the provider with current user data
  void initialize() {
    _currentPatientId = _appState.getAuthenticatedUser()?.patientId;
    _tryCacheExistingImage();
    print('🔧 ProfilePictureViewModel initialized for patient: $_currentPatientId');
  }

  /// Trigger initial profile image load after first frame
  void triggerInitialLoad() {
    if (_isInitialLoadTriggered) return;
    _isInitialLoadTriggered = true;

    final patientID = _appState.getAuthenticatedUser()?.patientId;
    if (patientID == null) {
      print('⚠️ No authenticated user found');
      return;
    }

    print('📥 Loading fresh profile image from API for patient: $patientID');
    loadProfileImage(forceRefresh: false);
  }

  /// Pre-cache already-loaded image bytes so we don't flash default avatar
  void _tryCacheExistingImage() {
    final imageData = _appState.getProfileImageData;
    if (imageData != null && imageData.isNotEmpty) {
      try {
        _cachedImageBytes = base64Decode(imageData);
        _cachedImageDataHash = '${imageData.length}_${imageData.hashCode}';
      } catch (e) {
        _cachedImageBytes = null;
        _cachedImageDataHash = null;
      }
    }
  }

  /// Check if authenticated user has changed (family member switch)
  /// Returns true if user has changed
  bool checkForUserSwitch() {
    final currentPatientId = _appState.getAuthenticatedUser()?.patientId;

    if (currentPatientId != null && currentPatientId != _currentPatientId) {
      _handleUserSwitch(currentPatientId);
      return true;
    }
    return false;
  }

  /// Handle user switch scenario - clear caches and load new user's image
  void _handleUserSwitch(int newPatientId) {
    final oldPatientId = _currentPatientId;
    _currentPatientId = newPatientId;

    // Clear AppState cache
    _appState.clearProfileImageCache();

    // Clear ViewModel cache
    _profileSettingsViewModel.clearProfileImageCache();

    // Clear local decoded bytes cache
    _cachedImageBytes = null;
    _cachedImageDataHash = null;
    _selectedImage = null;

    notifyListeners();

    // Load new user's profile image
    _profileSettingsViewModel.getProfileImage(
      patientID: newPatientId,
      forceRefresh: true,
      onSuccess: (data) {
        _tryCacheExistingImage();
        notifyListeners();
      },
      onError: (error) {
        notifyListeners();
      },
    );
  }

  /// Load profile image from API
  void loadProfileImage({bool forceRefresh = false}) {
    // Check if profile image is already loaded in AppState (skip if forcing refresh)
    if (!forceRefresh && _appState.getProfileImageData != null && _appState.getProfileImageData!.isNotEmpty) {
      return;
    }

    final patientID = _appState.getAuthenticatedUser()?.patientId;
    if (patientID == null) {
      return;
    }

    _profileSettingsViewModel.getProfileImage(
      patientID: patientID,
      forceRefresh: forceRefresh,
      onSuccess: (data) {
        _tryCacheExistingImage();
        notifyListeners();
      },
      onError: (error) {
        print('❌ Error loading profile image: $error');
      },
    );
  }

  /// Set selected image file (during upload process)
  void setSelectedImage(File? file) {
    _selectedImage = file;
    notifyListeners();
  }

  /// Pick image from camera or gallery with compression
  Future<void> pickImage(
    BuildContext context, {
    required void Function(
      BuildContext context,
      bool showFiles,
      Function(String, File) onImageSelected, {
      required Future<bool> Function() checkCameraPermission,
      required Future<bool> Function() checkGalleryPermission,
    }) showImagePicker,
    required Future<File?> Function(File) compressImage,
    required Function(String) onSuccess,
    required Function(String) onError,
    required String imageSizeTooLargeMessage,
    required String failedToProcessImageMessage,
    required Future<bool> Function(BuildContext) checkCameraPermission,
    required Future<bool> Function(BuildContext) checkGalleryPermission,
  }) async {
    // Show image picker options
    showImagePicker(
      context,
      false, // Don't show files option, only camera and gallery
      (base64String, file) async {
        try {

          // Compress and resize the image
          print('Calling compressAndResizeImage...');
          final compressedFile = await compressImage(file);

          File finalFile;
          String finalBase64;

          if (compressedFile == null) {
            print('⚠️ Compression failed - using original file as fallback');

            // Fallback: use original image if compression fails
            final originalSize = await file.length();
            final maxSize = 1048576; // 1MB

            if (originalSize > maxSize) {
              print('❌ Original file is too large: ${originalSize / 1024} KB');
              onError(imageSizeTooLargeMessage);
              return;
            }

            print('✅ Using original file (${originalSize / 1024} KB)');
            finalFile = file;
            var bytes = await file.readAsBytes();
            finalBase64 = base64.encode(bytes);
          } else {
            // Check compressed file size
            final fileSize = await compressedFile.length();
            final maxSize = 1048576; // 1MB
            print('✅ Compression successful: ${fileSize / 1024} KB');

            if (fileSize > maxSize) {
              print('❌ Compressed file still too large');
              onError(imageSizeTooLargeMessage);
              return;
            }

            finalFile = compressedFile;
            var bytes = await compressedFile.readAsBytes();
            finalBase64 = base64.encode(bytes);
          }

          print('Converting to base64... Length: ${finalBase64.length}');

          // Set selected image
          setSelectedImage(finalFile);

          print('📤 Starting upload...');
          // Upload the image
          uploadProfileImage(finalBase64, onSuccess: onSuccess, onError: onError);

          print('=== Image processing complete ===');
        } catch (e, stackTrace) {
          print('❌ Error in pickImage: $e');
          print('Stack trace: $stackTrace');
          onError(failedToProcessImageMessage);
        }
      },
      checkCameraPermission: () => checkCameraPermission(context),
      checkGalleryPermission: () => checkGalleryPermission(context),
    );
  }

  /// Upload profile image
  void uploadProfileImage(
    String base64String, {
    required Function(String) onSuccess,
    required Function(String) onError,
  }) {
    final patientID = _appState.getAuthenticatedUser()?.patientId;
    if (patientID == null) {
      onError('No authenticated user found');
      return;
    }
    _profileSettingsViewModel.uploadProfileImage(
      patientID: patientID,
      imageData: base64String,
      onSuccess: (data) async {
        // Clear old cache first to ensure fresh data
        _cachedImageBytes = null;
        _cachedImageDataHash = null;

        // Add a small delay to ensure AppState is fully updated
        await Future.delayed(const Duration(milliseconds: 50));

        // Update cached bytes with the new data from AppState
        _tryCacheExistingImage();
        _selectedImage = null; // Clear selected image after successful upload

        // Increment version to trigger targeted rebuild (no full screen refresh)
        _profileImageVersion.value++;

        final String successMessage = data is String
            ? data
            : (data is Map && data['message'] != null
                ? data['message'].toString()
                : data?.toString() ?? 'Success');
        onSuccess(successMessage);
      },
      onError: (error) {
        print('❌ Error uploading profile image: $error');
        onError(error);
      },
    );
  }

  /// Update cached image bytes if source data has changed
  void updateCacheIfNeeded() {
    final String? imageData = _appState.getProfileImageData;
    final String? currentHash = (imageData != null && imageData.isNotEmpty) ? '${imageData.length}_${imageData.hashCode}' : null;

    // Re-decode only if the underlying data actually changed
    if (currentHash != null && currentHash != _cachedImageDataHash) {
      try {
        _cachedImageBytes = base64Decode(imageData!);
        _cachedImageDataHash = currentHash;
      } catch (e) {
        print('❌ Error decoding profile image: $e');
        _cachedImageBytes = null;
        _cachedImageDataHash = null;
      }
    } else if (currentHash == null) {
      _cachedImageBytes = null;
      _cachedImageDataHash = null;
    }
  }

  /// Clear all cached data
  void clearCache() {
    _cachedImageBytes = null;
    _cachedImageDataHash = null;
    _selectedImage = null;
    notifyListeners();
  }

  /// Check if we should show shimmer loading
  bool shouldShowShimmer() {
    return _profileSettingsViewModel.isProfileImageLoading && _cachedImageBytes == null && _selectedImage == null;
  }

  @override
  void dispose() {
    _profileImageVersion.dispose();
    print('🗑️ ProfilePictureViewModel disposed');
    super.dispose();
  }
}
