import 'dart:io';

import 'package:csv/csv.dart';
import 'package:excel/excel.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:generp/Models/financeModels/paymentRequisitionPaymentsDetailsResponse.dart';
import 'package:generp/Models/financeModels/paymentRequisitionPaymentsListResponse.dart';
import 'package:generp/Notifiers/HomeScreenNotifier.dart';
import 'package:generp/services/api_calling.dart';
import 'package:path_provider/path_provider.dart';
import 'package:pdf/pdf.dart';
import 'package:pdf/widgets.dart' as pw;
import 'package:permission_handler/permission_handler.dart';
import 'package:printing/printing.dart';
import 'package:provider/provider.dart';

import '../../Utils/commonServices.dart';

class Paymentrequisitionpaymentslistprovider extends ChangeNotifier {
  bool _showMoreDetails = false;
  List<PaymentsList> _paymentsList = [];
  PaymentDetails _paymentDetails = PaymentDetails();
  List<String> _headings = [];
  List<String> _subHeadings = [];
  List<PaymentsList> get paymentsList => _paymentsList;
  PaymentDetails get paymentDetails => _paymentDetails;
  bool _isLoading = true;
  List<String> get Headings => _headings;
  List<String> get subHeadings => _subHeadings;
  bool get isLoading => _isLoading;
  bool get showMoreDetails => _showMoreDetails;

  set showMoreDetails(bool value) {
    _showMoreDetails = value;
    notifyListeners();
  }

  bool _isLoadingMore = false;
  bool get isLoadingMore => _isLoadingMore;

  bool _hasMoreData = true;
  bool get hasMoreData => _hasMoreData;

  int _currentPage = 1;
  String? _errorMessage;
  String? get errorMessage => _errorMessage;

  /// Reset pagination before new filter or refresh
  void resetPagination() {
    _currentPage = 1;
    _hasMoreData = true;
    _paymentsList.clear();
    notifyListeners();
  }

  Future<void> paymentsListAPI(
    BuildContext context,
    String from,
    String to, {
    bool append = false,
  }) async {
    try {
      var prov = Provider.of<HomescreenNotifier>(context, listen: false);

      if (!append) {
        _isLoading = true;
        _errorMessage = null;
        notifyListeners();
      } else {
        _isLoadingMore = true;
        notifyListeners();
      }

      final data = await ApiCalling.paymentRequisitionPaymentListAPI(
        prov.empId,
        prov.session,
        from,
        to,
        _currentPage.toString(), //  pass page number
      );
      debugPrint(
        'empId: ${prov.empId}, session: ${prov.session}, pageNumber: $_currentPage',
      );

      if (data != null && data.error == "0") {
        if (append) {
          _paymentsList.addAll(data.paymentsList ?? []);
        } else {
          _paymentsList = data.paymentsList ?? [];
        }

        if (data.paymentsList == null || data.paymentsList!.length < 10) {
          _hasMoreData = false; // no more pages
        }
      } else {
        if (!append) _errorMessage = "No data found!";
        _hasMoreData = false;
      }
    } catch (e) {
      _errorMessage = "Error: $e";
    }

    _isLoading = false;
    _isLoadingMore = false;
    notifyListeners();
  }

  /// Load next page
  Future<void> loadMore(BuildContext context, String from, String to) async {
    if (_isLoadingMore || !_hasMoreData) return;
    _currentPage++;
    await paymentsListAPI(context, from, to, append: true);
  }

  Future<void> paymentsListDetailsAPI(context, paymentId) async {
    try {
      var prov = Provider.of<HomescreenNotifier>(context, listen: false);
      final data = await ApiCalling.paymentRequisitionPaymentDetailsAPI(
        prov.empId,
        prov.session,
        paymentId,
      );
      if (data != null) {
        if (data.error == "0") {
          _paymentDetails =
              data.paymentDetails ??
              PaymentDetails(
                accountId: "-",
                accountName: "-",
                amount: "-",
                attachmentDirFilePath: "-",
                attachmentViewFileName: "-",
                createdDatetime: "-",
                description: "-",
                id: "-",
                updatedDatetime: "-",
                refType: "-",
                refId: "-",
                paymentRemarks: "-",
                paymentReferenceNumber: "-",
                paymentModeId: "-",
                paymentEmployeeName: "-",
                paymentDate: "-",
                paymentAccountName: "-",
                paymentAccountId: "-",
                mode: "-",
                isExists: "-",
                createdEmployeeId: "-",
                bankUpiId: "-",
                bankName: "-",
                bankIfscCode: "-",
                bankBranchName: "-",
                bankAccountNumber: "-",
                bankAccountHolderName: "-",
              );
          _headings = [
            "From Account",
            "Payment Mode",
            "Created Employee",
            "Attachment",
            "Payment Date",
            "Note",
            "Bank Name",
            "Bank Branch Name",
            "Bank IFSC Code",
            "Bank Holder Name",
            "Bank Account Number",
            "Bank UPI ID",
            "Payment Reference Number",
            "Created Date Time",
            "Updated Date Time",
          ];
          _subHeadings = [
            _paymentDetails.paymentAccountName ?? "-",
            _paymentDetails.mode ?? "-",
            _paymentDetails.paymentEmployeeName ?? "-",
            _paymentDetails.attachmentDirFilePath ?? "-",
            _paymentDetails.paymentDate ?? "-",
            _paymentDetails.paymentRemarks ?? "-",
            _paymentDetails.bankName ?? "-",
            _paymentDetails.bankBranchName ?? "-",
            _paymentDetails.bankIfscCode ?? "-",
            _paymentDetails.bankAccountHolderName ?? "-",
            _paymentDetails.bankAccountNumber ?? "-",
            _paymentDetails.bankUpiId ?? "-",
            _paymentDetails.paymentReferenceNumber ?? "-",
            _paymentDetails.createdDatetime ?? "-",
            _paymentDetails.updatedDatetime ?? "-",
          ];
          notifyListeners();
        }
      }
    } catch (e) {}
  }

  List<List<String>> prepareExportData() {
    final headers = [
      'ID',
      'Payment Account',
      'Amount',
      'Branch',
      'Account Number',
      'Description',
      'Mode',
      'Payment Reference Number',
      'Created Employee',
      'Date',
    ];

    final rows =
        paymentsList
            .map(
              (item) => [
                item.id ?? '',
                item.payAccount ?? '',
                item.amount ?? '',
                item.bankName ?? "",
                item.bankBranchName ?? '',
                item.bankAccountNumber ?? '',
                item.description ?? '',
                item.requestMode ?? '',
                item.paymentReferenceNumber ?? '',
                item.createdEmployee ?? '',
                item.createdDatetime ?? '',
              ],
            )
            .toList();

    return [headers, ...rows];
  }

  void copyToClipboard(BuildContext context) async {
    try {
      if (paymentsList.isEmpty) {
        ScaffoldMessenger.of(
          context,
        ).showSnackBar(SnackBar(content: Text("No data to copy")));
        return;
      }
      final data = prepareExportData();
      String raw = data.map((row) => row.join('\t')).join('\n');
      print('Clipboard data: $raw');
      await Clipboard.setData(ClipboardData(text: raw));
      toast(context, "Copied to Clipboard");
    } catch (e) {
      print('Error copying to clipboard: $e');
    }
  }

  Future<String> getSaveDirectory() async {
    // Try Downloads directory first
    try {
      if (Platform.isAndroid) {
        // Request storage permission for Android
        if (await Permission.storage.request().isGranted ||
            await Permission.manageExternalStorage.request().isGranted) {
          final dir = await getApplicationDocumentsDirectory();
          print('Using Downloads directory: ${dir.path}');
          return dir.path;
        }
      }
    } catch (e) {
      print('Error accessing Downloads directory: $e');
    }

    // Fallback to shared Documents directory
    try {
      final dir = await getDownloadsDirectory();
      if (dir != null) {
        final customDir = Directory('${dir.path}/RequisitionData');
        if (!await customDir.exists()) {
          await customDir.create(recursive: true);
        }
        print('Using custom Documents directory: ${customDir.path}');
        return customDir.path;
      }
    } catch (e) {
      print('Error accessing Documents directory: $e');
    }

    // Final fallback to app's Documents directory
    final dir = await getApplicationDocumentsDirectory();
    print('Using app Documents directory: ${dir.path}');
    return dir.path;
  }

  Future<void> downloadCSV(BuildContext context) async {
    try {
      if (paymentsList.isEmpty) {
        ScaffoldMessenger.of(
          context,
        ).showSnackBar(SnackBar(content: Text("No data to export")));
        return;
      }
      final data = prepareExportData();
      final csvData = const ListToCsvConverter().convert(data);
      final dirPath = await getSaveDirectory();
      final file = File('$dirPath/requisition_data.csv');
      await file.writeAsString(csvData);
      print('CSV saved at: ${file.path}');
      bool exists = await file.exists();
      print('File exists: $exists');
      // await OpenFile.open(file.path); // Open the file
      // await Share.share(file.path); // Share the file
      toast(context, "CSV Downloaded");
    } catch (e) {
      print('Error downloading CSV: $e');
    }
  }

  Future<void> downloadXLS(BuildContext context) async {
    try {
      if (paymentsList.isEmpty) {
        toast(context, "No Data to export");
        return;
      }
      final data = prepareExportData();
      var excel = Excel.createExcel();
      Sheet sheet = excel['Sheet1'];
      for (var row in data) {
        sheet.appendRow(row.map((cell) => TextCellValue(cell)).toList());
      }
      final dirPath = await getSaveDirectory();
      final file = File('$dirPath/requisition_data.xlsx');
      final bytes = excel.encode();
      if (bytes == null) throw Exception("Excel encoding failed");
      await file.writeAsBytes(bytes);
      print('XLSX saved at: ${file.path}');
      bool exists = await file.exists();
      print('File exists: $exists');
      // await OpenFile.open(file.path); // Open the file
      // await Share.share([file.path], text: 'Requisition Data XLSX'); // Share the file
      toast(context, ("XLSX Downloaded and opened"));
    } catch (e) {
      print('Error downloading XLSX: $e');
    }
  }

  Future<void> downloadPDF(BuildContext context) async {
    try {
      if (paymentsList.isEmpty) {
        toast(context, "No Data to export");
        return;
      }
      final data = prepareExportData();
      final pdf = pw.Document();
      pdf.addPage(
        pw.Page(build: (context) => pw.Table.fromTextArray(data: data)),
      );
      final dirPath = await getSaveDirectory();
      final file = File('$dirPath/requisition_data.pdf');
      await file.writeAsBytes(await pdf.save());
      print('PDF saved at: ${file.path}');
      bool exists = await file.exists();
      print('File exists: $exists');
      // await OpenFile.open(file.path); // Open the file
      // await Share.shareXFiles([file.path], text: 'Requisition Data PDF'); // Share the file
      toast(context, "PDF Downloaded ");
    } catch (e) {
      print('Error downloading PDF: $e');
    }
  }

  Future<void> printData(BuildContext context) async {
    try {
      if (paymentsList.isEmpty) {
        toast(context, "No Data to Print");
        return;
      }
      final data = prepareExportData();
      final pdf = pw.Document();
      pdf.addPage(
        pw.Page(build: (context) => pw.Table.fromTextArray(data: data)),
      );
      await Printing.layoutPdf(
        onLayout: (PdfPageFormat format) async => pdf.save(),
      );
    } catch (e) {
      print('Error printing data: $e');
    }
  }

  void resetForm() {
    _paymentsList = [];
    _paymentDetails = PaymentDetails();
    _headings = [];
    _subHeadings = [];
  }
}
