import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'package:cashumit/models/local_receipt.dart';
import 'package:cashumit/models/receipt_item.dart';
import 'package:cashumit/services/firefly_api_service.dart';

class LocalReceiptService {
  static const String _receiptsKey = 'local_receipts';

  /// Save a receipt to local storage
  static Future<void> saveReceipt(LocalReceipt receipt) async {
    final prefs = await SharedPreferences.getInstance();
    final receipts = await getReceipts();

    // Check if receipt with the same ID already exists
    final existingIndex = receipts.indexWhere((r) => r.id == receipt.id);

    if (existingIndex != -1) {
      // Replace existing receipt
      receipts[existingIndex] = receipt;
    } else {
      // Add new receipt
      receipts.add(receipt);
    }

    // Convert receipts to JSON strings
    final receiptJsonList =
        receipts.map((receipt) => json.encode(receipt.toJson())).toList();

    await prefs.setStringList(_receiptsKey, receiptJsonList);
  }

  /// Get all receipts from local storage
  static Future<List<LocalReceipt>> getReceipts() async {
    final prefs = await SharedPreferences.getInstance();
    final receiptJsonList = prefs.getStringList(_receiptsKey) ?? [];

    return receiptJsonList
        .map((jsonString) => LocalReceipt.fromJson(json.decode(jsonString)))
        .toList();
  }

  /// Get unsubmitted receipts from local storage
  static Future<List<LocalReceipt>> getUnsubmittedReceipts() async {
    final allReceipts = await getReceipts();
    return allReceipts.where((receipt) => !receipt.isSubmitted).toList();
  }

  /// Get submitted receipts from local storage
  static Future<List<LocalReceipt>> getSubmittedReceipts() async {
    final allReceipts = await getReceipts();
    return allReceipts.where((receipt) => receipt.isSubmitted).toList();
  }

  /// Update a receipt's submission status
  static Future<void> updateReceiptSubmissionStatus(String receiptId,
      {bool? isSubmitted, String? submissionError}) async {
    final prefs = await SharedPreferences.getInstance();
    final receipts = await getReceipts();

    final receiptIndex = receipts.indexWhere((r) => r.id == receiptId);

    if (receiptIndex != -1) {
      final receipt = receipts[receiptIndex];
      receipts[receiptIndex] = receipt.copyWith(
        isSubmitted: isSubmitted ?? receipt.isSubmitted,
        submissionError: submissionError ?? receipt.submissionError,
        submittedAt: isSubmitted == true ? DateTime.now() : receipt.submittedAt,
      );

      // Convert receipts to JSON strings
      final receiptJsonList =
          receipts.map((receipt) => json.encode(receipt.toJson())).toList();

      await prefs.setStringList(_receiptsKey, receiptJsonList);
    }
  }

  /// Remove a receipt from local storage
  static Future<void> removeReceipt(String receiptId) async {
    final prefs = await SharedPreferences.getInstance();
    final receipts = await getReceipts();

    final filteredReceipts =
        receipts.where((receipt) => receipt.id != receiptId).toList();

    // Convert receipts to JSON strings
    final receiptJsonList = filteredReceipts
        .map((receipt) => json.encode(receipt.toJson()))
        .toList();

    await prefs.setStringList(_receiptsKey, receiptJsonList);
  }

  /// Clear all receipts from local storage
  static Future<void> clearAllReceipts() async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove(_receiptsKey);
  }

  /// Submit a single receipt to FireFly III
  static Future<bool> submitReceiptToServer(
    LocalReceipt receipt,
    String baseUrl,
    String accessToken,
  ) async {
    try {
      // Check if the receipt is already submitted
      if (receipt.isSubmitted) {
        return true; // Already submitted
      }

      // Validate required fields
      final groupsWithItems =
          receipt.groups.where((g) => g.items.isNotEmpty).toList();
      if (groupsWithItems.isEmpty) {
        await updateReceiptSubmissionStatus(receipt.id,
            isSubmitted: false, submissionError: 'Tidak ada item');
        return false;
      }
      if (receipt.destinationAccountId == null) {
        await updateReceiptSubmissionStatus(receipt.id,
            isSubmitted: false, submissionError: 'Missing destination account');
        return false;
      }
      final missingSource =
          groupsWithItems.any((g) => g.sourceAccountId == null);
      if (missingSource) {
        await updateReceiptSubmissionStatus(receipt.id,
            isSubmitted: false, submissionError: 'Missing source account');
        return false;
      }

      // Submit to FireFly III
      final transactionId = await _submitToFireFly(
        receipt: receipt,
        baseUrl: baseUrl,
        accessToken: accessToken,
      );

      if (transactionId != null) {
        // Update receipt status to submitted
        await updateReceiptSubmissionStatus(receipt.id,
            isSubmitted: true, submissionError: null);
        return true;
      } else {
        await updateReceiptSubmissionStatus(receipt.id,
            isSubmitted: false, submissionError: 'Failed to submit to server');
        return false;
      }
    } catch (e) {
      await updateReceiptSubmissionStatus(receipt.id,
          isSubmitted: false, submissionError: e.toString());
      return false;
    }
  }

  /// Submit all unsubmitted receipts to FireFly III
  static Future<Map<String, dynamic>> submitAllUnsubmittedReceipts(
    String baseUrl,
    String accessToken,
  ) async {
    // Cek koneksi server terlebih dahulu
    final isServerAvailable = await FireflyApiService.testConnection(
      baseUrl: baseUrl,
    );

    if (!isServerAvailable) {
      // Jika server tidak tersedia, hanya kembalikan status tanpa mencoba submit
      final unsubmittedReceipts = await getUnsubmittedReceipts();
      final results = <String, bool>{};

      for (final receipt in unsubmittedReceipts) {
        results[receipt.id] = false;
      }

      return {
        'results': results,
        'successCount': 0,
        'failureCount': unsubmittedReceipts.length,
        'totalCount': unsubmittedReceipts.length,
        'serverAvailable': false,
        'message': 'Server tidak tersedia, tidak ada transaksi yang dikirim',
      };
    }

    final unsubmittedReceipts = await getUnsubmittedReceipts();
    final results = <String, bool>{};
    int successCount = 0;
    int failureCount = 0;

    for (final receipt in unsubmittedReceipts) {
      try {
        final success =
            await submitReceiptToServer(receipt, baseUrl, accessToken);
        results[receipt.id] = success;

        if (success) {
          successCount++;
        } else {
          failureCount++;
        }
      } catch (e) {
        results[receipt.id] = false;
        failureCount++;
        // Update the receipt with the error
        await updateReceiptSubmissionStatus(receipt.id,
            isSubmitted: false, submissionError: e.toString());
      }
    }

    return {
      'results': results,
      'successCount': successCount,
      'failureCount': failureCount,
      'totalCount': unsubmittedReceipts.length,
      'serverAvailable': true,
    };
  }

  /// Private method to handle actual submission to FireFly III
  static Future<String?> _submitToFireFly({
    required LocalReceipt receipt,
    required String baseUrl,
    required String accessToken,
  }) async {
    try {
      final groupsWithItems =
          receipt.groups.where((g) => g.items.isNotEmpty).toList();
      if (groupsWithItems.isEmpty) return null;

      // Format tanggal dengan jam
      String two(int v) => v.toString().padLeft(2, '0');
      final fireflyDate =
          '${receipt.transactionDate.year}-${two(receipt.transactionDate.month)}-${two(receipt.transactionDate.day)}T${two(receipt.transactionDate.hour)}:${two(receipt.transactionDate.minute)}:${two(receipt.transactionDate.second)}';

      final transactionIds = <String>[];
      final transactionUrls = <String>[];

      // Submit satu transaksi per grup
      for (final group in groupsWithItems) {
        if (group.sourceAccountId == null ||
            receipt.destinationAccountId == null) {
          continue;
        }

        final groupTotal = group.total;
        final description = group.sourceAccountName != null
            ? '${group.sourceAccountName} - ${_generateTransactionDescription(group.items)}'
            : _generateTransactionDescription(group.items);

        final id = await FireflyApiService.submitDummyTransaction(
          baseUrl: baseUrl,
          accessToken: accessToken,
          sourceId: group.sourceAccountId!,
          destinationId: receipt.destinationAccountId!,
          type: 'deposit',
          description: description,
          date: fireflyDate,
          amount: groupTotal.toStringAsFixed(2),
        );

        if (id != null && id != 'success') {
          transactionIds.add(id);
          transactionUrls.add('$baseUrl/transactions/show/$id');
        }
      }

      // Submit transaksi tip jika aktif
      if (receipt.hasTip &&
          receipt.tipSourceAccountId != null &&
          receipt.destinationAccountId != null) {
        final tipAmount = receipt.tipAmount;
        final tipId = await FireflyApiService.submitDummyTransaction(
          baseUrl: baseUrl,
          accessToken: accessToken,
          sourceId: receipt.tipSourceAccountId!,
          destinationId: receipt.destinationAccountId!,
          type: 'deposit',
          description: 'Tip dari kembalian',
          date: fireflyDate,
          amount: tipAmount.toStringAsFixed(2),
        );

        if (tipId != null && tipId != 'success') {
          transactionIds.add(tipId);
          transactionUrls.add('$baseUrl/transactions/show/$tipId');
        }
      }

      // Update receipt dengan ID dan URL
      if (transactionIds.isNotEmpty) {
        final updatedReceipt = receipt.copyWith(
          fireflyTransactionId: transactionIds.first,
          fireflyTransactionIds: transactionIds,
          fireflyTransactionUrl: transactionUrls.isNotEmpty
              ? transactionUrls.first
              : null,
          fireflyTransactionUrls: transactionUrls,
        );
        await saveReceipt(updatedReceipt);
      }

      return transactionIds.isNotEmpty ? transactionIds.first : null;
    } catch (e) {
      print('Error submitting receipt to FireFly III: $e');
      return null;
    }
  }

  /// Generate transaction description
  static String _generateTransactionDescription(List<ReceiptItem> items) {
    if (items.isEmpty) {
      return 'Transaksi Struk Belanja';
    }

    // Take the first 5 item descriptions
    final itemNames = items.take(5).map((item) => item.description).toList();

    // If there are more than 5 items, append ', dll' to the last item
    if (items.length > 5) {
      itemNames[4] += ', dll';
    }

    // Join the item names with ', '
    return itemNames.join(', ');
  }
}
