import 'dart:developer';
import 'dart:typed_data';
import 'dart:convert';
import 'package:base_project/model/system_params_model.dart';
import 'package:base_project/repository/system_params_repo.dart';
import 'package:base_project/utils/managers/user_manager.dart';
import 'package:base_project/utils/toast_messages/toast_message_util.dart';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';

import '../../core/providers/dynamic_theme_provider.dart';

class SystemParamsViewModel extends ChangeNotifier {
  final _repo = SystemParamsRepo();

  Uint8List? _profileImageBytes;
  XFile? _profileImage;
  bool _loading = false;

  // Store system parameters as model
  SystemParamsModel? _systemParams;
  Map<String, dynamic> _systemParamsList = {};

  // Getter for system parameters model
  SystemParamsModel? get systemParams => _systemParams;

  // Getter for system parameters list (for backward compatibility)
  Map<String, dynamic> get systemParamsList => _systemParamsList;

  // Getter for profile image bytes
  Uint8List? get profileImageBytes => _profileImageBytes;

  // Getter for profile image
  XFile? get profileImg => _profileImage;

  // Getter for loading status
  bool get loading => _loading;

  // Setter for loading status with notification to listeners
  set loading(bool value) {
    _loading = value;
    notifyListeners();
  }

  // Setter for profile image
  setImage(XFile? val) {
    _profileImage = val;
    // Avoid notify during build; schedule for next frame
    WidgetsBinding.instance.addPostFrameCallback((_) {
      notifyListeners();
    });
  }

  // Setter for profile image bytes
  setProfileImageBytes(Uint8List? val) {
    _profileImageBytes = val;
    // Avoid notify during build; schedule for next frame
    WidgetsBinding.instance.addPostFrameCallback((_) {
      notifyListeners();
    });
    // Persist to SharedPreferences for future sessions
    _persistLogoToLocal(val);
  }

  // Method to pick an image from the gallery
  void pickImg(BuildContext context) async {
    final ImagePicker picker = ImagePicker();
    final XFile? image = await picker.pickImage(source: ImageSource.gallery);

    if (image != null) {
      setImage(image);
      // Convert image to bytes and store
      final bytes = await image.readAsBytes();
      setProfileImageBytes(bytes);

      // Generate dynamic theme IMMEDIATELY when image is selected
      print("Image selected - generating dynamic theme immediately...");
      await _generateDynamicThemeFromLogo(context);
      print("Dynamic theme generated immediately after image selection!");

      // Show success message
      ToastMessageUtil.showToast(
          message:
              "Logo selected! Dynamic theme applied. Click 'Upload Logo' to save permanently.",
          toastType: ToastType.success);
    } else {
      ToastMessageUtil.showToast(
          message: "No image picked !!", toastType: ToastType.warning);
    }
  }

  // Method to upload logo image separately (like edit profile)
  Future<void> uploadLogo(BuildContext context) async {
    if (_profileImage == null) {
      ToastMessageUtil.showToast(
          message: "Please pick an image first!", toastType: ToastType.warning);
      return;
    }

    loading = true;
    try {
      Uint8List fileBytes = await _profileImage!.readAsBytes();
      print("Logo file size: ${fileBytes.length} bytes");

      // Generate dynamic theme IMMEDIATELY after image selection (before API call)
      print("Generating dynamic theme immediately...");
      await _generateDynamicThemeFromLogo(context);
      print(
          "Dynamic theme generated immediately - user sees instant feedback!");

      // Now proceed with API upload
      FormData formData = FormData.fromMap({
        'imageFile': MultipartFile.fromBytes(
          fileBytes,
          filename: _profileImage!.name,
        ),
      });

      dynamic uploadResult;
      try {
        uploadResult = await _repo.uploadSystemParamLogo(formData);
        print("----LOGO-UPLOADED----");
        print(uploadResult);
      } catch (e) {
        // If backend returns intermittent error but file actually uploaded,
        // avoid showing a scary error immediately. Log and proceed to metadata update.
        print("Upload API error (may be intermittent): $e");
      }

      // Try to update system parameters regardless (backend may have the file already)
      bool metaUpdated = false;
      try {
        await _updateLogoInSystemParams();
        metaUpdated = true;
      } catch (e) {
        print("Logo metadata update failed: $e");
      }

      loading = false;

      if (metaUpdated || uploadResult != null) {
        ToastMessageUtil.showToast(
            message: "Company logo uploaded! Dynamic theme applied.",
            toastType: ToastType.success);
      } else {
        ToastMessageUtil.showToast(
            message: "Logo upload may have failed. Please retry.",
            toastType: ToastType.warning);
      }
    } catch (error) {
      loading = false;
      print("Error uploading logo: $error");
      ToastMessageUtil.showToast(
          message: "Error uploading logo: ${error.toString()}",
          toastType: ToastType.error);
      // Even if API fails, theme is already applied - user keeps the visual benefit!
      print(
          "API failed but dynamic theme is already applied - user keeps the visual benefit!");
    }
  }

  // Generate dynamic theme from logo
  Future<void> _generateDynamicThemeFromLogo(BuildContext context) async {
    try {
      print("_generateDynamicThemeFromLogo called");
      print("_profileImageBytes is null: ${_profileImageBytes == null}");
      print("_profileImageBytes length: ${_profileImageBytes?.length ?? 0}");

      if (_profileImageBytes != null) {
        final dynamicThemeProvider =
            Provider.of<DynamicThemeProvider>(context, listen: false);
        print("DynamicThemeProvider found: ${dynamicThemeProvider != null}");
        print(
            "Before theme generation - isUsingDynamicTheme: ${dynamicThemeProvider.isUsingDynamicTheme}");

        await dynamicThemeProvider.generateThemeFromLogo(_profileImageBytes!);

        print(
            "After theme generation - isUsingDynamicTheme: ${dynamicThemeProvider.isUsingDynamicTheme}");
        print("Dynamic theme generated successfully from logo!");
      } else {
        print("_profileImageBytes is null, cannot generate theme");
      }
    } catch (error) {
      print("Error generating dynamic theme: $error");
    }
  }

  // Update system parameters to include logo information
  Future<void> _updateLogoInSystemParams() async {
    try {
      final logoData = {
        'upload_Logo': _profileImageBytes,
        'upload_Logo_name': _profileImage?.name ?? 'logo.png',
        'upload_Logo_path': _profileImage?.path ?? '',
      };

      await _repo.updateSystemParameters(logoData);
      print("Logo info updated in system parameters");
    } catch (error) {
      print("Error updating logo info in system params: $error");
    }
  }

  // Method to fetch system parameters and store them in the model
  Future<void> getSystemParams() async {
    loading = true;

    try {
      final value = await _repo.getSystemParameters();
      print("----SYSTEM-PARAMS----");

      // Normalize response to Map<String, dynamic>
      Map<String, dynamic> normalized = {};
      if (value is Map<String, dynamic>) {
        normalized = value;
      } else if (value != null) {
        try {
          normalized = Map<String, dynamic>.from(value as Map);
        } catch (_) {
          normalized = {};
        }
      }

      // Store in both formats for backward compatibility
      _systemParamsList = normalized;
      _systemParams = SystemParamsModel.fromJson(normalized);

      // Load existing logo if available
      _loadExistingLogo(value);

      loading = false;
      print(normalized);
    } catch (error) {
      loading = false;
      print("Error-$error");
    }
  }

  // Load existing logo from system parameters
  void _loadExistingLogo(Map<String, dynamic> systemParams) {
    try {
      // Check if logo data exists in system parameters
      if (systemParams['upload_Logo'] != null) {
        // If logo is stored as base64 string
        if (systemParams['upload_Logo'] is String) {
          final String base64Image = systemParams['upload_Logo'];
          if (base64Image.isNotEmpty) {
            // Remove data URL prefix if present and decode base64
            String cleanBase64 = base64Image;
            if (base64Image.contains(',')) {
              cleanBase64 = base64Image.split(',').last;
            }
            try {
              final Uint8List imageBytes = base64Decode(cleanBase64);
              setProfileImageBytes(imageBytes);
              print("Existing logo loaded from system parameters");
            } catch (e) {
              print("Error decoding logo: $e");
            }
          }
        }
        // If logo is stored as bytes
        else if (systemParams['upload_Logo'] is List) {
          final List<int> logoBytes =
              List<int>.from(systemParams['upload_Logo']);
          setProfileImageBytes(Uint8List.fromList(logoBytes));
          print("Existing logo loaded from system parameters");
        }
      }
    } catch (error) {
      print("Error loading existing logo: $error");
    }
    // Also attempt to load from local storage if not present in systemParams
    if (_profileImageBytes == null) {
      _loadLogoFromLocal();
    }
  }

  // Method to update system parameters
  Future<void> updateSystemParams(Map<String, dynamic> body) async {
    loading = true;

    try {
      // Convert the form data to proper backend format
      final backendData = _convertFormDataToBackendFormat(body);

      final value = await _repo.updateSystemParameters(backendData);
      print("----SYSTEM-PARAMS-UPDATED----");
      loading = false;
      print(value);
      ToastMessageUtil.showToast(
          message: "System parameters updated!!", toastType: ToastType.success);
    } catch (error) {
      loading = false;
      print("Error-$error");
      ToastMessageUtil.showToast(
          message: error.toString(), toastType: ToastType.error);
    }
  }

  // Convert form data to backend format
  Map<String, dynamic> _convertFormDataToBackendFormat(
      Map<String, dynamic> formData) {
    final Map<String, dynamic> backendData = {};

    // Map form field names to backend field names
    for (String key in formData.keys) {
      switch (key) {
        case 'Scheduler Timer':
          backendData['schedulerTime'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'Lease Tax Code':
          backendData['leaseTaxCode'] = formData[key];
          break;
        case 'Vessel Confirmation':
          backendData['vesselConfProcessLimit'] =
              int.tryParse(formData[key]) ?? 0;
          break;
        case 'Row to Display':
          backendData['rowToDisplay'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'Link to Display':
          backendData['linkToDisplay'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'Row to Add':
          backendData['rowToAdd'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'LOV Row to Display':
          backendData['lovRowToDisplay'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'LOV Link to Display':
          backendData['lovLinkToDisplay'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'OID Server Name':
          backendData['oidserverName'] = formData[key];
          break;
        case 'OID Base':
          backendData['oidBase'] = formData[key];
          break;
        case 'OID Admin User':
          backendData['oidAdminUser'] = formData[key];
          break;
        case 'OID Server Port':
          backendData['oidServerPort'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'User Default Group':
          backendData['userDefaultGroup'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'Default Department':
          backendData['defaultDepartment'] = formData[key];
          break;
        case 'Default Position':
          backendData['defaultPosition'] = formData[key];
          break;
        case 'Single Charge':
          backendData['singleCharge'] = formData[key];
          break;
        case 'First Day of the Week':
          backendData['firstDayOftheWeek'] = formData[key];
          break;
        case 'Hours Per Shift':
          backendData['hourPerShift'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'CN Billing Frequency':
          backendData['cnBillingFrequency'] = int.tryParse(formData[key]) ?? 0;
          break;
        case 'Billing Department Code':
          backendData['billingDepartmentCode'] = formData[key];
          break;
        case 'Base Price List':
          backendData['basePriceList'] = formData[key];
          break;
        case 'Non-Container Service Order':
          backendData['nonContainerServiceOrder'] = formData[key];
          break;
        case 'EDI MAE Scheduler':
          backendData['ediMaeSchedulerONOFF'] =
              int.tryParse(formData[key]) ?? 0;
          break;
        case 'EDI Scheduler':
          backendData['ediSchedulerONOFF'] = formData[key];
          break;
        case 'Company Name':
          backendData['Company_Display_Name'] = formData[key];
          break;
        case 'Registration Allowed':
          backendData['isRegitrationAllowed'] = formData[key] == 'true';
          break;
        default:
          // For any unmapped fields, pass through as is
          backendData[key] = formData[key];
          break;
      }
    }

    // Add logo upload fields if available
    if (_profileImageBytes != null) {
      backendData['upload_Logo'] = _profileImageBytes;
      backendData['upload_Logo_name'] = _profileImage?.name ?? 'logo.png';
      backendData['upload_Logo_path'] = _profileImage?.path ?? '';
    }

    return backendData;
  }

  // Updating the profile image
  Future<void> updateImage(BuildContext context) async {
    if (_profileImage == null) return; // Ensure an image is selected

    loading = true;
    Uint8List fileBytes = await _profileImage!.readAsBytes();

    FormData formData = FormData.fromMap({
      'imageFile': MultipartFile.fromBytes(
        fileBytes,
        filename: _profileImage!.name,
      ),
    });

    _repo.updateProfileImg(formData).then((value) {
      log("Image Update--$value");
      loading = false;
      ToastMessageUtil.showToast(
          message: "Profile Image Updated", toastType: ToastType.success);
    }).onError((error, stackTrace) {
      log("Error Updating Image--$error");
      loading = false;
      // setUpdating(false);
      ToastMessageUtil.showToast(
          message: "Error updating image!!", toastType: ToastType.error);
    });
  }

  // Method to clear logo and reset theme
  Future<void> clearLogo(BuildContext context) async {
    try {
      // Clear the image data
      setImage(null);
      setProfileImageBytes(null);

      // Reset to default theme
      final dynamicThemeProvider =
          Provider.of<DynamicThemeProvider>(context, listen: false);
      dynamicThemeProvider.resetToDefaultTheme();
      print("Logo cleared and theme reset to default");

      // Update system parameters to remove logo info
      await _updateLogoInSystemParams();
      // Remove locally persisted logo
      final prefs = await SharedPreferences.getInstance();
      await prefs.remove('cached_logo_bytes');

      ToastMessageUtil.showToast(
          message: "Logo cleared! Theme reset to default.",
          toastType: ToastType.info);
    } catch (error) {
      print("Error clearing logo: $error");
      ToastMessageUtil.showToast(
          message: "Error clearing logo: ${error.toString()}",
          toastType: ToastType.error);
    }
  }

  // Persist logo bytes locally
  Future<void> _persistLogoToLocal(Uint8List? bytes) async {
    try {
      final prefs = await SharedPreferences.getInstance();
      if (bytes == null || bytes.isEmpty) {
        await prefs.remove('cached_logo_bytes');
        return;
      }
      final base64Str = base64Encode(bytes);
      await prefs.setString('cached_logo_bytes', base64Str);
    } catch (e) {
      print('Error persisting logo locally: $e');
    }
  }

  // Load logo bytes from local storage
  Future<void> _loadLogoFromLocal() async {
    try {
      final prefs = await SharedPreferences.getInstance();
      final base64Str = prefs.getString('cached_logo_bytes');
      if (base64Str != null && base64Str.isNotEmpty) {
        final bytes = base64Decode(base64Str);
        setProfileImageBytes(bytes);
        print('Loaded logo from local storage');
      }
    } catch (e) {
      print('Error loading logo from local storage: $e');
    }
  }
}
