// lib/providers/receipt_provider.dart

import 'package:flutter/material.dart';
import 'package:cashumit/providers/receipt_state.dart';
import 'package:cashumit/models/receipt_item.dart';
import 'package:cashumit/services/receipt_service.dart'; // Pastikan ReceiptService sudah dibuat
import 'package:cashumit/models/firefly_account.dart'; // Untuk tipe akun
import 'package:cashumit/models/local_receipt.dart';
import 'package:cashumit/services/local_receipt_service.dart';
import 'package:cashumit/services/account_cache_service.dart';
import 'dart:math';

class ReceiptProvider with ChangeNotifier {
  late ReceiptState _state;

  ReceiptState get state => _state;

  ReceiptProvider() {
    _state = ReceiptState();
  }

  /// Inisialisasi state awal
  Future<void> initialize() async {
    await loadCredentialsAndAccounts();
    // Bisa menambahkan inisialisasi lain jika diperlukan
  }

  /// Memuat kredensial dan akun
  Future<void> loadCredentialsAndAccounts() async {
    final credentials = await ReceiptService.loadCredentials();

    if (credentials == null) {
      // Jika tidak ada kredensial, kita tetap perlu memberitahu listener bahwa state berubah
      // (misalnya untuk menampilkan pesan error di UI)
      _state = _state.copyWith(
        fireflyUrl: null,
        accessToken: null,
        accounts: [], // Kosongkan akun juga
      );
      notifyListeners();
      return;
    }

    // Periksa apakah kredensial berubah
    final credentialsChanged = _state.fireflyUrl != credentials['url'] ||
        _state.accessToken != credentials['token'];

    _state = _state.copyWith(
      fireflyUrl: credentials['url'],
      accessToken: credentials['token'],
    );
    notifyListeners();

    // Jika kredensial ada dan berubah, lanjutkan untuk memuat akun
    if (credentialsChanged) {
      await loadAccounts();
      // Juga perbarui cache akun dari server
      try {
        await ReceiptService.updateAccountCache(
          baseUrl: _state.fireflyUrl!,
          accessToken: _state.accessToken!,
        );
      } catch (e) {
        print('Gagal memperbarui cache akun: $e');
      }
    } else if (_state.accounts.isEmpty) {
      // Jika akun belum pernah dimuat, muat sekarang
      await loadAccounts();
    }
  }

  /// Memuat daftar akun dengan prioritas: server > cache > fallback
  Future<void> loadAccounts() async {
    if (_state.fireflyUrl == null || _state.accessToken == null) {
      // Jika kredensial tidak ada, coba ambil dari cache
      final cachedAccounts = await AccountCacheService.getCachedAccounts();
      if (cachedAccounts.isNotEmpty) {
        _state = _state.copyWith(accounts: cachedAccounts);
        notifyListeners();
      }
      return;
    }

    // Gunakan cache service untuk mendapatkan akun dengan prioritas
    final allAccounts =
        await AccountCacheService.getAccountsWithFallback(() async {
      final accounts = await ReceiptService.loadAccounts(
        baseUrl: _state.fireflyUrl!,
        accessToken: _state.accessToken!,
      );
      // Perbarui cache dengan data terbaru dari server
      await ReceiptService.saveAccountsToCache(accounts);
      return accounts;
    });

    _state = _state.copyWith(accounts: allAccounts);
    notifyListeners();
  }

  /// Menambahkan item ke receipt
  void addItem(ReceiptItem item) {
    _state = _state.copyWith(
      items: [..._state.items, item],
    );
    notifyListeners();
  }

  /// Mengedit item di receipt
  void editItem(int index, ReceiptItem newItem) {
    if (index < 0 || index >= _state.items.length) return;

    final updatedItems = List<ReceiptItem>.from(_state.items);
    updatedItems[index] = newItem;

    _state = _state.copyWith(
      items: updatedItems,
    );
    notifyListeners();
  }

  /// Menghapus item dari receipt
  void removeItem(int index) {
    if (index < 0 || index >= _state.items.length) return;

    final updatedItems = List<ReceiptItem>.from(_state.items)..removeAt(index);

    _state = _state.copyWith(
      items: updatedItems,
    );
    notifyListeners();
  }

  /// Memilih akun sumber
  void selectSourceAccount(String id, String name) {
    _state = _state.copyWith(
      sourceAccountId: id,
      sourceAccountName: name,
    );
    notifyListeners();
  }

  /// Memilih akun tujuan
  void selectDestinationAccount(String id, String name) {
    _state = _state.copyWith(
      destinationAccountId: id,
      destinationAccountName: name,
    );
    notifyListeners();
  }

  /// Mencari ID akun berdasarkan nama dan tipe
  String? findAccountIdByName(String name, String expectedType) {
    return ReceiptService.findAccountIdByName(
      name: name,
      expectedType: expectedType,
      accounts: _state.accounts,
    );
  }

  /// Mengirim transaksi (ini akan memanggil ReceiptService dan mungkin memperbarui state setelahnya)
  Future<String?> submitTransaction() async {
    if (_state.items.isEmpty) {
      throw Exception('Tidak ada item untuk dikirim');
    }

    if (_state.fireflyUrl == null || _state.accessToken == null) {
      throw Exception('Kredensial Firefly III tidak ditemukan');
    }

    // Pastikan akun sumber dan tujuan dipilih
    // Logika untuk mencari ID berdasarkan nama jika diperlukan bisa ditambahkan di sini
    // atau diharapkan UI sudah menangani ini sebelum memanggil submitTransaction

    if (_state.sourceAccountId == null || _state.destinationAccountId == null) {
      throw Exception('Akun sumber dan tujuan harus dipilih');
    }

    final transactionId = await ReceiptService.submitTransaction(
      items: _state.items,
      transactionDate: _state.transactionDate,
      sourceAccountId: _state.sourceAccountId!,
      destinationAccountId: _state.destinationAccountId!,
      accounts: _state.accounts,
      baseUrl: _state.fireflyUrl!,
      accessToken: _state.accessToken!,
    );

    return transactionId;
  }

  /// Simpan transaksi ke penyimpanan lokal (ini akan menyimpan transaksi lokal bukan langsung submit ke server)
  Future<String?> saveTransactionLocally() async {
    if (_state.items.isEmpty) {
      throw Exception('Tidak ada item untuk disimpan');
    }

    if (_state.sourceAccountId == null || _state.destinationAccountId == null) {
      throw Exception('Akun sumber dan tujuan harus dipilih');
    }

    // Buat ID unik untuk receipt lokal
    final receiptId =
        'receipt_${DateTime.now().millisecondsSinceEpoch}_${Random().nextInt(1000)}';

    // Generate transaction description
    final transactionDescription =
        _generateTransactionDescription(_state.items);

    // Buat objek LocalReceipt
    final localReceipt = LocalReceipt(
      id: receiptId,
      items: _state.items,
      sourceAccountId: _state.sourceAccountId,
      sourceAccountName: _state.sourceAccountName,
      destinationAccountId: _state.destinationAccountId,
      destinationAccountName: _state.destinationAccountName,
      transactionDate: _state.transactionDate,
      transactionDescription: transactionDescription,
      createdAt: DateTime.now(),
    );

    // Simpan ke penyimpanan lokal
    await LocalReceiptService.saveReceipt(localReceipt);

    // Kosongkan items di state setelah disimpan
    _state = _state.copyWith(
      items: [],
      sourceAccountId: null,
      sourceAccountName: null,
      destinationAccountId: null,
      destinationAccountName: null,
    );
    notifyListeners();

    return receiptId;
  }

  /// Submit semua receipt lokal yang belum terkirim ke server
  Future<Map<String, dynamic>> submitAllLocalReceipts() async {
    if (_state.fireflyUrl == null || _state.accessToken == null) {
      throw Exception('Kredensial Firefly III tidak ditemukan');
    }

    // Submit semua receipt lokal yang belum terkirim
    final result = await LocalReceiptService.submitAllUnsubmittedReceipts(
      _state.fireflyUrl!,
      _state.accessToken!,
    );

    notifyListeners(); // Update UI jika ada perubahan
    return result;
  }

  /// Generate transaction description from items
  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(', ');
  }

  // Tambahkan metode lain sesuai kebutuhan, seperti untuk memperbarui transactionDate jika diperlukan
}
