import 'dart:async';
import 'package:flutter/material.dart';
import 'package:cashumit/models/receipt_item.dart';
import 'package:cashumit/screens/add_item_screen.dart';
import 'package:bluetooth_print/bluetooth_print.dart';
import 'package:cashumit/services/bluetooth_service.dart';
import 'package:cashumit/widgets/receipt_body.dart';
import 'package:cashumit/widgets/receipt_tear_effect.dart';
import 'package:cashumit/widgets/store_info_config_dialog.dart';
import 'package:cashumit/widgets/custom_text_config_dialog.dart';
import 'package:cashumit/widgets/receipt_speed_dial.dart';
import 'package:cashumit/widgets/printing_status_card.dart';
import 'package:cashumit/widgets/transaction_submission_dialog.dart';
import 'package:cashumit/models/group_submission_result.dart';

import 'package:cashumit/services/account_dialog_service.dart';
import 'package:cashumit/services/esc_pos_print_service.dart';
import 'package:cashumit/services/receipt_service.dart';

import 'package:provider/provider.dart';
import 'package:cashumit/providers/receipt_provider.dart';

import 'dart:io';
import 'package:flutter/services.dart';

class ReceiptScreen extends StatefulWidget {
  const ReceiptScreen({super.key});

  @override
  State<ReceiptScreen> createState() => _ReceiptScreenState();
}

class _ReceiptScreenState extends State<ReceiptScreen> {
  final BluetoothService _bluetoothService = BluetoothService();
  bool _isPrinting = false;

  // Simpan subscription agar bisa dibatalkan (perbaikan memory leak).
  StreamSubscription? _bluetoothStateSubscription;

  @override
  void initState() {
    super.initState();
    _initBluetooth();
    _loadSavedBluetoothDevice();

    WidgetsBinding.instance.addPostFrameCallback((_) {
      final receiptProvider = context.read<ReceiptProvider>();
      receiptProvider.initialize();
    });
  }

  @override
  void dispose() {
    _bluetoothStateSubscription?.cancel();
    super.dispose();
  }

  Future<void> _loadSavedBluetoothDevice() async {
    await _bluetoothService.loadSavedDevice();
  }

  Future<bool> _checkBluetoothConnection() async {
    return await _bluetoothService.checkConnection();
  }

  Future<void> _initBluetooth() async {
    await _bluetoothService.initialize();

    // Simpan subscription agar bisa dibatalkan di dispose.
    _bluetoothStateSubscription = _bluetoothService.state.listen((state) {
      if (!mounted) return;
      switch (state) {
        case BluetoothPrint.connected:
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Printer terhubung')),
          );
          break;
        case BluetoothPrint.disconnected:
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Printer terputus')),
          );
          break;
        default:
          break;
      }
    });
  }

  Future<void> _printToThermalPrinter() async {
    final receiptProvider = context.read<ReceiptProvider>();
    final state = receiptProvider.state;

    try {
      final isConnected = await _bluetoothService.reconnectIfNeeded();
      if (!isConnected) {
        if (!mounted) return;
        if (_bluetoothService.connectedDevice != null) {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(content: Text('Gagal menyambungkan ke printer')),
          );
        } else {
          ScaffoldMessenger.of(context).showSnackBar(
            const SnackBar(
                content: Text('Harap hubungkan printer terlebih dahulu')),
          );
        }
        return;
      }

      await EscPosPrintService.printToThermalPrinter(
        groups: state.groups,
        transactionDate: state.transactionDate,
        destinationAccountName: state.destinationAccountName,
        context: context,
        bluetoothService: _bluetoothService,
        paymentInfo: PaymentInfo(
          paymentAmount: state.paymentAmount,
          isTip: state.hasTip,
        ),
        tipSourceAccountName: state.tipSourceAccountName,
      );

      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Perintah cetak dikirim ke printer')),
      );
    } on SocketException catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Koneksi ke printer terputus: ${e.message}')),
      );
    } on PlatformException catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Error printer: ${e.message}')),
      );
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Gagal mencetak struk: $e')),
      );
    }
  }

  void _startPrinting() {
    setState(() => _isPrinting = true);
  }

  void _endPrinting() {
    setState(() => _isPrinting = false);
  }

  // ============ GRUP & ITEM ============

  void _addGroup() {
    context.read<ReceiptProvider>().addGroup();
  }

  void _removeGroup(String groupId) {
    context.read<ReceiptProvider>().removeGroup(groupId);
  }

  void _addItem(String groupId) async {
    final newItem = await showDialog<ReceiptItem>(
      context: context,
      builder: (context) => const AddItemScreen(),
    );
    if (newItem != null) {
      context.read<ReceiptProvider>().addItem(groupId, newItem);
    }
  }

  void _editItem(String groupId, int index) async {
    final receiptProvider = context.read<ReceiptProvider>();
    final group =
        receiptProvider.state.groups.firstWhere((g) => g.id == groupId);
    if (index < 0 || index >= group.items.length) {
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          const SnackBar(
              content: Text("Gagal mengedit item: Index tidak valid.")),
        );
      }
      return;
    }

    final originalItem = group.items[index];
    final editedItem = await showDialog<ReceiptItem>(
      context: context,
      builder: (context) => AddItemScreen.fromItem(originalItem),
    );

    if (editedItem != null) {
      receiptProvider.editItem(groupId, index, editedItem);
    }
  }

  void _removeItem(String groupId, int index) {
    final receiptProvider = context.read<ReceiptProvider>();
    final group =
        receiptProvider.state.groups.firstWhere((g) => g.id == groupId);
    if (index < 0 || index >= group.items.length) return;
    receiptProvider.removeItem(groupId, index);
  }

  // ============ AKUN ============

  Future<void> _selectGroupSource(String groupId) async {
    final receiptProvider = context.read<ReceiptProvider>();
    final selectedAccount = await AccountDialogService.showSourceAccountDialog(
        context, receiptProvider.state.accounts);
    if (selectedAccount != null) {
      receiptProvider.selectGroupSource(
        groupId,
        selectedAccount['id'].toString(),
        selectedAccount['name'].toString(),
      );
    }
  }

  // ============ TIP ============

  Future<void> _setTipSource() async {
    final receiptProvider = context.read<ReceiptProvider>();
    final selectedAccount = await AccountDialogService.showSourceAccountDialog(
        context, receiptProvider.state.accounts);
    if (selectedAccount != null) {
      receiptProvider.setTipSourceAccount(
        selectedAccount['id'].toString(),
        selectedAccount['name'].toString(),
      );
    }
  }

  void _clearTip() {
    context.read<ReceiptProvider>().clearTip();
  }

  // ============ TANGGAL ============

  Future<void> _changeDate() async {
    final receiptProvider = context.read<ReceiptProvider>();
    final currentDate = receiptProvider.state.transactionDate;

    final pickedDate = await showDatePicker(
      context: context,
      initialDate: currentDate,
      firstDate: DateTime(2000),
      lastDate: DateTime(2100),
    );
    if (pickedDate == null) return;

    if (!mounted) return;
    final pickedTime = await showTimePicker(
      context: context,
      initialTime: TimeOfDay.fromDateTime(currentDate),
    );
    if (pickedTime == null) return;

    final newDate = DateTime(
      pickedDate.year,
      pickedDate.month,
      pickedDate.day,
      pickedTime.hour,
      pickedTime.minute,
    );
    receiptProvider.setTransactionDate(newDate);
  }

  // ============ FIREFLY ============

  Future<void> _sendToFirefly() async {
    final receiptProvider = context.read<ReceiptProvider>();
    final state = receiptProvider.state;

    // Validasi awal
    final groupsWithItems =
        state.groups.where((g) => g.items.isNotEmpty).toList();
    if (groupsWithItems.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Tidak ada item untuk dikirim')),
      );
      return;
    }
    if (state.destinationAccountId == null ||
        state.fireflyUrl == null ||
        state.accessToken == null) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(
            content: Text('Akun tujuan / kredensial belum lengkap')),
      );
      return;
    }

    // Hitung tipAmount jika tip aktif
    final hasTip = state.hasTip;
    final tipAmount = hasTip ? state.tipAmount : null;

    // Bangun daftar task dari state struk saat ini
    final tasks = ReceiptService.buildTasksFromReceipt(
      groups: groupsWithItems,
      destinationAccountId: state.destinationAccountId!,
      destinationAccountName: state.destinationAccountName ?? '',
      transactionDate: state.transactionDate,
      tipSourceAccountId: hasTip ? state.tipSourceAccountId : null,
      tipSourceAccountName: hasTip ? state.tipSourceAccountName : null,
      tipAmount: tipAmount,
    );

    // Tampilkan popup pengiriman
    final results = await showDialog<List<GroupSubmissionResult>>(
      context: context,
      barrierDismissible: false,
      builder: (context) => TransactionSubmissionDialog(
        tasks: tasks,
        baseUrl: state.fireflyUrl!,
        accessToken: state.accessToken!,
      ),
    );

    if (results == null) return;
    if (!mounted) return;

    final successes =
        results.where((r) => r.isSuccess && r.transactionId != null).toList();
    final failures = results.where((r) => r.isFailed).toList();

    // Link transaksi yang berhasil dapat di-copy/open langsung dari popup card.
    // Simpan grup yang gagal sebagai nota lokal + reset state.
    await receiptProvider.saveFailedGroupsLocally(results);

    if (!mounted) return;
    if (failures.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
              '${successes.length} transaksi berhasil dikirim ke Firefly III'),
        ),
      );
    } else {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(
              '${successes.length} berhasil, ${failures.length} gagal disimpan sebagai nota lokal'),
          duration: const Duration(seconds: 4),
        ),
      );
    }
  }

  // ============ CONFIG DIALOGS ============

  Future<void> _openStoreInfoConfig() async {
    await showDialog<bool>(
      context: context,
      builder: (context) => const StoreInfoConfigDialog(),
    );
    // Refresh store info widget setelah dialog tutup
    if (mounted) {
      setState(() {});
    }
  }

  Future<void> _openCustomTextConfig() async {
    await showDialog<bool>(
      context: context,
      builder: (context) => const CustomTextConfigDialog(),
    );
    if (mounted) {
      setState(() {});
    }
  }

  void _openSettings() async {
    final result = await Navigator.pushNamed(context, '/config');
    if (result == true) {
      context.read<ReceiptProvider>().loadCredentialsAndAccounts();
    }
  }

  void _openLocalReceipts() async {
    await Navigator.pushNamed(context, '/local-receipts');
  }

  @override
  Widget build(BuildContext context) {
    final receiptProvider = context.watch<ReceiptProvider>();
    final state = receiptProvider.state;

    return Scaffold(
      backgroundColor: Colors.grey[300],
      floatingActionButton: ReceiptSpeedDial(
        bluetoothService: _bluetoothService,
        onCheckConnection: _checkBluetoothConnection,
        onPrint: _printToThermalPrinter,
        onSettings: _openSettings,
        onReloadAccounts: receiptProvider.loadAccounts,
        hasItems: state.hasItems,
        allGroupsHaveSource: state.allGroupsHaveSource,
        hasDestination: state.destinationAccountId != null,
        onSendToFirefly: _sendToFirefly,
        onPrintingStart: _startPrinting,
        onPrintingEnd: _endPrinting,
        onOpenLocalReceipts: _openLocalReceipts,
      ),
      body: Stack(
        children: [
          Center(
            child: SingleChildScrollView(
              child: Container(
                width: 360,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.center,
                  children: [
                    // Tear effect atas
                    Container(
                      color: const Color(0xFFE0E0E0),
                      child: const Column(
                        children: [
                          SizedBox(height: 15),
                          ReceiptTearTop(),
                        ],
                      ),
                    ),

                    // Receipt body
                    ReceiptBody(
                      groups: state.groups,
                      transactionDate: state.transactionDate,
                      onOpenStoreInfoConfig: _openStoreInfoConfig,
                      onChangeDate: _changeDate,
                      onOpenCustomTextConfig: _openCustomTextConfig,
                      total: state.total,
                      onEditItem: (groupId, index) =>
                          _editItem(groupId, index),
                      onRemoveItem: (groupId, index) =>
                          _removeItem(groupId, index),
                      onAddItem: (groupId) => _addItem(groupId),
                      onRemoveGroup: (groupId) => _removeGroup(groupId),
                      onSelectGroupSource: (groupId) =>
                          _selectGroupSource(groupId),
                      onAddGroup: _addGroup,
                      onSetTip: _setTipSource,
                      onClearTip: _clearTip,
                    ),

                    // Tear effect bawah
                    Container(
                      color: const Color(0xFFE0E0E0),
                      child: const Column(
                        children: [
                          ReceiptTearBottom(),
                          SizedBox(height: 15),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            ),
          ),
          if (_isPrinting)
            PrintingStatusCard(
              isVisible: _isPrinting,
              onDismiss: () {
                setState(() => _isPrinting = false);
              },
            ),
        ],
      ),
    );
  }
}
