// payment_request_controller.dart
import 'dart:io';
import 'dart:convert';
import 'package:get/get.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mime/mime.dart';
import 'package:intl/intl.dart';

import 'package:on_field_work/helpers/services/api_service.dart';
import 'package:on_field_work/helpers/services/app_logger.dart';
import 'package:on_field_work/helpers/widgets/my_snackbar.dart';
import 'package:on_field_work/helpers/widgets/time_stamp_image_helper.dart';
import 'package:on_field_work/model/finance/expense_category_model.dart';
import 'package:on_field_work/model/finance/currency_list_model.dart';
import 'package:on_field_work/model/employees/employee_model.dart';

class AddPaymentRequestController extends GetxController {
  // Loading States
  final isLoadingPayees = false.obs;
  final isLoadingCategories = false.obs;
  final isLoadingCurrencies = false.obs;
  final isProcessingAttachment = false.obs;
  final isSubmitting = false.obs;

  // Data Lists
  final payees = <String>[].obs;
  final categories = <ExpenseCategory>[].obs;
  final currencies = <Currency>[].obs;
  final globalProjects = <Map<String, dynamic>>[].obs;

  // Selected Values
  final selectedProject = Rx<Map<String, dynamic>?>(null);
  final selectedCategory = Rx<ExpenseCategory?>(null);
  final selectedPayee = Rx<EmployeeModel?>(null);
  final selectedCurrency = Rx<Currency?>(null);
  final isAdvancePayment = false.obs;
  final selectedDueDate = Rx<DateTime?>(null);

  // Text Controllers
  final titleController = TextEditingController();
  final dueDateController = TextEditingController();
  final amountController = TextEditingController();
  final descriptionController = TextEditingController();
  final removedAttachments = <Map<String, dynamic>>[].obs;

  // Attachments
  final attachments = <File>[].obs;
  final existingAttachments = <Map<String, dynamic>>[].obs;
  final ImagePicker _picker = ImagePicker();

  @override
  void onInit() {
    super.onInit();
    fetchAllMasterData();
    fetchGlobalProjects();
  }

  @override
  void onClose() {
    titleController.dispose();
    dueDateController.dispose();
    amountController.dispose();
    descriptionController.dispose();
    super.onClose();
  }

  /// Fetch all master data concurrently
  Future<void> fetchAllMasterData() async {
    await Future.wait([
      _fetchData(
          payees, ApiService.getExpensePaymentRequestPayeeApi, isLoadingPayees),
      _fetchData(categories, ApiService.getMasterExpenseCategoriesApi,
          isLoadingCategories),
      _fetchData(
          currencies, ApiService.getMasterCurrenciesApi, isLoadingCurrencies),
    ]);
  }

  /// Generic fetch handler
  Future<void> _fetchData<T>(
      RxList<T> list, Future<dynamic> Function() apiCall, RxBool loader) async {
    try {
      loader.value = true;
      final response = await apiCall();
      if (response != null && response.data.isNotEmpty) {
        list.value = response.data;
      } else {
        list.clear();
      }
    } catch (e) {
      logSafe("Error fetching data: $e", level: LogLevel.error);
      list.clear();
    } finally {
      loader.value = false;
    }
  }

  /// Fetch projects
  Future<void> fetchGlobalProjects() async {
    try {
      final response = await ApiService.getGlobalProjects();
      globalProjects.value = (response ?? [])
          .map<Map<String, dynamic>>((e) => {
                'id': e['id']?.toString() ?? '',
                'name': e['name']?.toString().trim() ?? '',
              })
          .where((p) => p['id']!.isNotEmpty && p['name']!.isNotEmpty)
          .toList();
    } catch (e) {
      logSafe("Error fetching projects: $e", level: LogLevel.error);
      globalProjects.clear();
    }
  }

  /// Pick due date
  Future<void> pickDueDate(BuildContext context) async {
    final pickedDate = await showDatePicker(
      context: context,
      initialDate: selectedDueDate.value ?? DateTime.now(),
      firstDate: DateTime(DateTime.now().year - 5),
      lastDate: DateTime(DateTime.now().year + 5),
    );

    if (pickedDate != null) {
      selectedDueDate.value = pickedDate;
      dueDateController.text = DateFormat('dd MMM yyyy').format(pickedDate);
    }
  }

  /// Generic file picker for multiple sources
  Future<void> pickAttachments(
      {bool fromGallery = false, bool fromCamera = false}) async {
    try {
      if (fromCamera) {
        final pickedFile = await _picker.pickImage(source: ImageSource.camera);
        if (pickedFile != null) {
          isProcessingAttachment.value = true;
          final timestamped = await TimestampImageHelper.addTimestamp(
              imageFile: File(pickedFile.path));
          attachments.add(timestamped);
        }
      } else if (fromGallery) {
        final pickedFile = await _picker.pickImage(source: ImageSource.gallery);
        if (pickedFile != null) attachments.add(File(pickedFile.path));
      } else {
        final result = await FilePicker.platform
            .pickFiles(type: FileType.any, allowMultiple: true);
        if (result != null && result.paths.isNotEmpty)
          attachments.addAll(result.paths.whereType<String>().map(File.new));
      }
      attachments.refresh();
    } catch (e) {
      _errorSnackbar("Attachment error: $e");
    } finally {
      isProcessingAttachment.value = false;
    }
  }

  Future<void> pickFromCamera() async {
    try {
      final pickedFile = await _picker.pickImage(source: ImageSource.camera);
      if (pickedFile != null) {
        isProcessingAttachment.value = true;
        File imageFile = File(pickedFile.path);

        // Add timestamp to the captured image
        File timestampedFile = await TimestampImageHelper.addTimestamp(
          imageFile: imageFile,
        );

        attachments.add(timestampedFile);
        attachments.refresh(); // refresh UI
      }
    } catch (e) {
      _errorSnackbar("Camera error: $e");
    } finally {
      isProcessingAttachment.value = false; // stop loading
    }
  }

  /// Selection handlers
  void selectProject(Map<String, dynamic> project) =>
      selectedProject.value = project;
  void selectCategory(ExpenseCategory category) =>
      selectedCategory.value = category;
  void selectPayee(EmployeeModel payee) => selectedPayee.value = payee;
  void selectCurrency(Currency currency) => selectedCurrency.value = currency;

  void addAttachment(File file) => attachments.add(file);
  void removeAttachment(File file) {
    if (attachments.contains(file)) {
      attachments.remove(file);
    }
  }

  void removeExistingAttachment(Map<String, dynamic> existingAttachment) {
    final index = existingAttachments.indexWhere(
        (e) => e['id'] == existingAttachment['id']); // match by normalized id

    if (index != -1) {
      // Mark as inactive
      existingAttachments[index]['isActive'] = false;
      existingAttachments.refresh();

      // Add to removedAttachments to inform API
      removedAttachments.add({
        "documentId": existingAttachment['id'], // ensure API receives id
        "isActive": false,
      });

      // Show snackbar feedback
      showAppSnackbar(
        title: 'Removed',
        message: 'Attachment has been removed.',
        type: SnackbarType.success,
      );
    }
  }

  /// Build attachment payload
  Future<List<Map<String, dynamic>>> buildAttachmentPayload() async {
    final existingPayload = existingAttachments
        .map((e) => {
              "documentId": e['id'], // use the normalized id
              "fileName": e['fileName'],
              "contentType": e['contentType'] ?? 'application/octet-stream',
              "fileSize": e['fileSize'] ?? 0,
              "description": "",
              "url": e['url'],
              "isActive": e['isActive'] ?? true,
            })
        .toList();

    final newPayload = await Future.wait(attachments.map((file) async {
      final bytes = await file.readAsBytes();
      return {
        "fileName": file.path.split('/').last,
        "base64Data": base64Encode(bytes),
        "contentType": lookupMimeType(file.path) ?? 'application/octet-stream',
        "fileSize": await file.length(),
        "description": "",
      };
    }));

    // Combine active + removed attachments
    return [...existingPayload, ...newPayload, ...removedAttachments];
  }

  /// Submit edited payment request
  Future<bool> submitEditedPaymentRequest({required String requestId}) async {
    if (isSubmitting.value) return false;

    try {
      isSubmitting.value = true;

      // Validate form
      if (!_validateForm()) return false;

      // Build attachment payload
      final billAttachments = await buildAttachmentPayload();

      final payload = {
        "id": requestId,
        "title": titleController.text.trim(),
        "projectId": selectedProject.value?['id'] ?? '',
        "expenseCategoryId": selectedCategory.value?.id ?? '',
        "amount": double.tryParse(amountController.text.trim()) ?? 0,
        "currencyId": selectedCurrency.value?.id ?? '',
        "description": descriptionController.text.trim(),
        "payee": selectedPayee.value?.id ?? "",
        "dueDate": selectedDueDate.value?.toIso8601String(),
        "isAdvancePayment": isAdvancePayment.value,
        "billAttachments": billAttachments.map((a) {
          return {
            "documentId": a['documentId'],
            "fileName": a['fileName'],
            "base64Data": a['base64Data'] ?? "",
            "contentType": a['contentType'],
            "fileSize": a['fileSize'],
            "description": a['description'] ?? "",
            "isActive": a['isActive'] ?? true,
          };
        }).toList(),
      };

      logSafe("💡 Submitting Edited Payment Request: ${jsonEncode(payload)}");

      final success = await ApiService.editExpensePaymentRequestApi(
        id: payload['id'],
        title: payload['title'],
        projectId: payload['projectId'],
        expenseCategoryId: payload['expenseCategoryId'],
        amount: payload['amount'],
        currencyId: payload['currencyId'],
        description: payload['description'],
        payee: payload['payee'],
        dueDate: payload['dueDate'] ?? '',
        isAdvancePayment: payload['isAdvancePayment'],
        billAttachments: payload['billAttachments'],
      );

      logSafe("💡 Edit Payment Request API Response: $success");

      if (success == true) {
        logSafe("✅ Payment request edited successfully.");
        return true;
      } else {
        return _errorSnackbar("Failed to edit payment request.");
      }
    } catch (e, st) {
      logSafe("💥 Submit Edited Payment Request Error: $e\n$st",
          level: LogLevel.error);
      return _errorSnackbar("Something went wrong. Please try again later.");
    } finally {
      isSubmitting.value = false;
    }
  }

  /// Submit payment request (Project API style)
  Future<bool> submitPaymentRequest() async {
    if (isSubmitting.value) return false;

    try {
      isSubmitting.value = true;

      // Validate form
      if (!_validateForm()) return false;

      // Build attachment payload
      final billAttachments = await buildAttachmentPayload();

      final payload = {
        "title": titleController.text.trim(),
        "projectId": selectedProject.value?['id'] ?? '',
        "expenseCategoryId": selectedCategory.value?.id ?? '',
        "amount": double.tryParse(amountController.text.trim()) ?? 0,
        "currencyId": selectedCurrency.value?.id ?? '',
        "description": descriptionController.text.trim(),
        "payee": selectedPayee.value?.id ?? "",
        "dueDate": selectedDueDate.value?.toIso8601String(),
        "isAdvancePayment": isAdvancePayment.value,
        "billAttachments": billAttachments.map((a) {
          return {
            "fileName": a['fileName'],
            "fileSize": a['fileSize'],
            "contentType": a['contentType'],
          };
        }).toList(),
      };

      logSafe("💡 Submitting Payment Request: ${jsonEncode(payload)}");

      final success = await ApiService.createExpensePaymentRequestApi(
        title: payload['title'],
        projectId: payload['projectId'],
        expenseCategoryId: payload['expenseCategoryId'],
        amount: payload['amount'],
        currencyId: payload['currencyId'],
        description: payload['description'],
        payee: payload['payee'],
        dueDate: selectedDueDate.value,
        isAdvancePayment: payload['isAdvancePayment'],
        billAttachments: billAttachments,
      );

      logSafe("💡 Payment Request API Response: $success");

      if (success == true) {
        logSafe("✅ Payment request created successfully.");
        return true;
      } else {
        return _errorSnackbar("Failed to create payment request.");
      }
    } catch (e, st) {
      logSafe("💥 Submit Payment Request Error: $e\n$st",
          level: LogLevel.error);
      return _errorSnackbar("Something went wrong. Please try again later.");
    } finally {
      isSubmitting.value = false;
    }
  }

  /// Form validation
  bool _validateForm() {
    if (selectedProject.value == null ||
        selectedProject.value!['id'].toString().isEmpty)
      return _errorSnackbar("Please select a project");
    if (selectedCategory.value == null)
      return _errorSnackbar("Please select a category");
    if (selectedPayee.value == null)
      return _errorSnackbar("Please select a payee");
    if (selectedCurrency.value == null)
      return _errorSnackbar("Please select currency");
    return true;
  }

  bool _errorSnackbar(String msg, [String title = "Error"]) {
    showAppSnackbar(title: title, message: msg, type: SnackbarType.error);
    return false;
  }

  /// Clear form
  void clearForm() {
    titleController.clear();
    dueDateController.clear();
    amountController.clear();
    descriptionController.clear();
    selectedProject.value = null;
    selectedCategory.value = null;
    selectedPayee.value = null;
    selectedCurrency.value = null;
    isAdvancePayment.value = false;
    attachments.clear();
    existingAttachments.clear();
    removedAttachments.clear();
  }
}
