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
      if (receipt.sourceAccountId == null ||
          receipt.destinationAccountId == null) {
        await updateReceiptSubmissionStatus(receipt.id,
            isSubmitted: false, submissionError: 'Missing account information');
        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 {
    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,
    };
  }

  /// 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 transactionId = await FireflyApiService.submitDummyTransaction(
        baseUrl: baseUrl,
        accessToken: accessToken,
        sourceId: receipt.sourceAccountId!,
        destinationId: receipt.destinationAccountId!,
        type: 'deposit', // Assuming deposit for receipts
        description: receipt.transactionDescription ??
            _generateTransactionDescription(receipt.items),
        date:
            '${receipt.transactionDate.year}-${receipt.transactionDate.month.toString().padLeft(2, '0')}-${receipt.transactionDate.day.toString().padLeft(2, '0')}',
        amount: receipt.total.toStringAsFixed(2),
      );

      // Jika transaksi berhasil dikirim, simpan transactionId dan URL
      if (transactionId != null) {
        // Update receipt dengan transactionId dan URL
        final updatedReceipt = receipt.copyWith(
          fireflyTransactionId: transactionId,
          fireflyTransactionUrl: '$baseUrl/transactions/show/$transactionId',
        );

        // Simpan kembali receipt yang diperbarui ke storage
        await saveReceipt(updatedReceipt);
      }

      return transactionId;
    } 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(', ');
  }
}
