import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/carton.dart';
import 'package:fcs/domain/entities/custom_duty.dart';
import 'package:fcs/domain/entities/discount.dart';
import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:fcs/domain/entities/invoice.dart';
import 'package:fcs/domain/entities/payment_method.dart';
import 'package:fcs/domain/entities/shipment.dart';
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/carton/model/carton_model.dart';
import 'package:fcs/pages/discount/model/discount_model.dart';
import 'package:fcs/pages/invoice/editor/invoice_carton_table.dart';
import 'package:fcs/pages/invoice/editor/invoice_discount_list.dart';
import 'package:fcs/pages/invoice/editor/invoice_handling_fee_list.dart';
import 'package:fcs/pages/invoice/invoice_table.dart';
import 'package:fcs/pages/invoice/model/invoice_model.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/payment_methods/model/payment_method_model.dart';
import 'package:fcs/pages/rates/custom_list.dart';
import 'package:fcs/pages/rates/model/shipment_rate_model.dart';
import 'package:fcs/pages/shipment/model/shipment_model.dart';
import 'package:fcs/pages/widgets/display_text.dart';
import 'package:fcs/pages/widgets/fcs_icons.dart';
import 'package:fcs/pages/widgets/local_button.dart';
import 'package:fcs/pages/widgets/local_dropdown.dart';
import 'package:fcs/pages/widgets/local_popup_menu_button.dart';
import 'package:fcs/pages/widgets/local_popupmenu.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/progress.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_icons/flutter_icons.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:intl/intl.dart';
import 'package:provider/provider.dart';

class InvoiceEditor extends StatefulWidget {
  final Invoice invoice;
  final User customer;
  final FcsShipment fcsShipment;
  InvoiceEditor({this.invoice, this.customer, this.fcsShipment});

  @override
  _InvoiceEditorState createState() => _InvoiceEditorState();
}

class _InvoiceEditorState extends State<InvoiceEditor> {
  var dateFormatter = new DateFormat('dd MMM yyyy');

  Invoice _invoice;
  bool _isLoading = false;
  bool _isNew;
  User _user;

  bool _showCartons = false;
  @override
  void initState() {
    super.initState();
    _isNew = widget.invoice == null;

    if (widget.invoice != null) {
      _invoice = widget.invoice;
    } else {
      _invoice = Invoice(
          customDuties: [],
          cartons: [],
          shipments: [],
          invoiceDate: DateTime.now());
    }
    _user = widget.customer;
    _loadAll();
  }

  _loadAll() async {
    setState(() {
      _isLoading = true;
    });
    try {
      await _loadCartons();
      await _loadShipments();
      await _loadDiscount();
    } catch (e) {} finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  _loadCartons() async {
    CartonModel cartonModel = Provider.of<CartonModel>(context, listen: false);
    List<Carton> cartons = await cartonModel.getCartonsForInvoice(
        widget.fcsShipment.id, widget.customer.id);
    cartons.forEach((c) {
      c.isChecked = true;
    });
    setState(() {
      _invoice.cartons = cartons;
    });
  }

  _loadShipments() async {
    ShipmentModel shipmentModel =
        Provider.of<ShipmentModel>(context, listen: false);
    List<Shipment> shipments = await shipmentModel.getShipmentWithHandlingFee(
        widget.fcsShipment.id, widget.customer.id);
    shipments.forEach((s) {
      s.isSelected = true;
    });
    setState(() {
      _invoice.shipments = shipments;
    });
  }

  List<Discount> discounts = [];
  _loadDiscount() async {
    DiscountModel discountModel =
        Provider.of<DiscountModel>(context, listen: false);
    discounts = await discountModel.getDiscount(widget.customer.id);
    if (discounts != null && discounts.length > 0) {
      setState(() {
        _invoice.discount = discounts.first;
      });
    }
  }

  @override
  void dispose() {
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    var mainModel = Provider.of<MainModel>(context);
    var paymentMethodModel = Provider.of<PaymentMethodModel>(context);
    var rateModel = Provider.of<ShipmentRateModel>(context);
    var rate = rateModel.rate;

    final invoiceNumberBox = DisplayText(
        labelTextKey: 'invoice.number',
        iconData: FontAwesomeIcons.fileInvoice,
        text: _invoice?.invoiceNumber ?? "");
    final statusBox = DisplayText(
        text: _invoice?.status ?? "",
        iconData: Icons.av_timer,
        labelTextKey: 'invoice.status');
    final cartonTable = InvoiceCartonTable(
      cartons: _invoice.cartons,
      rate: rate,
      onSelect: (c, checked) {
        setState(() {
          c.isChecked = checked;
        });
      },
    );
    final paymentTypesBox = LocalDropdown<PaymentMethod>(
      callback: (v) {
        setState(() {
          _invoice.paymentMethod = v;
        });
      },
      labelKey: "invoice.payment_method",
      iconData: FontAwesome.money,
      display: (u) => u.name,
      selectedValue: _invoice.paymentMethod,
      values: paymentMethodModel.paymentMethods,
    );
    final invoiceTableBox = InvoiceTable(
      invoice: _invoice,
      rate: rate,
      deliveryFeeSelected: (selected) {
        setState(() {
          if (selected) {
            _invoice.deliveryFee = rate.deliveryFee;
          } else {
            _invoice.deliveryFee = 0;
          }
        });
      },
      discountSelected: (discount) {
        setState(() {
          _invoice.discount = discount;
        });
      },
      onRemove: (i) {
        if (i.invoiceDataType == InvoiceDataType.CustomFeeDataType) {
          _removeCustom(i.data);
        }
        if (i.invoiceDataType == InvoiceDataType.DiscountDataType) {
          setState(() {
            _invoice.discount = null;
          });
        }
        if (i.invoiceDataType == InvoiceDataType.DeliveryFeeType) {
          setState(() {
            _invoice.deliveryFee = 0;
          });
        }
        if (i.invoiceDataType == InvoiceDataType.HandlingFeeType) {
          setState(() {
            _removeShipment(i.data);
          });
        }
      },
    );
    final toggleButtonsBox = ToggleButtons(
      color: Colors.black45,
      selectedColor: Colors.black45,
      disabledColor: Colors.grey,
      selectedBorderColor: primaryColor,
      borderColor: Colors.transparent,
      fillColor: Colors.transparent,
      highlightColor: Colors.black45,
      children: <Widget>[
        Icon(cartonIconData),
      ],
      onPressed: (int index) {
        setState(() {
          _showCartons = !_showCartons;
        });
      },
      isSelected: [_showCartons],
    );
    final popupMenu = LocalPopupMenuButton(
      buttonIcon: Icons.add_circle,
      selectable: false,
      buttonColor: Colors.black45,
      popmenus: [
        LocalPopupMenu(
          id: 1,
          textKey: "invoice.add.custom.fee.menu",
        ),
        LocalPopupMenu(
          id: 2,
          textKey: "invoice.add.handling.fee.menu",
        ),
        LocalPopupMenu(
          id: 3,
          textKey: "invoice.add.discount.menu",
        ),
        LocalPopupMenu(
          id: 4,
          textKey: "invoice.delivery_fee",
        )
      ],
      popupMenuCallback: (p) async {
        if (p.id == 1) {
          CustomDuty customDuty = await Navigator.of(context).push(
              CupertinoPageRoute(
                  builder: (context) => CustomList(selected: true)));
          _addCustom(customDuty);
        } else if (p.id == 2) {
          Shipment shipment = await Navigator.of(context).push(
              CupertinoPageRoute(
                  builder: (context) =>
                      InvoiceHandlingFeeList(shipments: _invoice.shipments)));
          _addShipment(shipment);
        } else if (p.id == 3) {
          Discount discount =
              await Navigator.of(context).push(CupertinoPageRoute(
                  builder: (context) => InvoiceDiscountList(
                        discounts: discounts,
                      )));
          if (discount != null) {
            setState(() {
              _invoice.discount = discount;
            });
          }
        } else if (p.id == 4) {
          setState(() {
            _invoice.deliveryFee = rate.deliveryFee;
          });
        }
      },
    );

    final headerBox = Row(
      crossAxisAlignment: CrossAxisAlignment.end,
      children: [
        Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(dateFormatter.format(_invoice.invoiceDate)),
            SizedBox(
              height: 10,
            ),
            Text(_user?.name ?? ""),
            Text(
              _user?.fcsID ?? "",
              style: TextStyle(fontSize: 12),
            )
          ],
        ),
        Spacer(),
        Row(
          mainAxisAlignment: MainAxisAlignment.end,
          children: [
            toggleButtonsBox,
            popupMenu,
          ],
        ),
      ],
    );

    final createBtn = LocalButton(
      textKey: "invoice.issue.btn",
      callBack: _save,
    );

    return LocalProgress(
      inAsyncCall: _isLoading,
      child: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          leading: new IconButton(
            icon: new Icon(CupertinoIcons.back, color: primaryColor),
            onPressed: () => Navigator.of(context).pop(),
          ),
          backgroundColor: Colors.white,
          shadowColor: Colors.transparent,
          title: LocalText(context, 'invoice.form.title',
              color: primaryColor, fontSize: 20),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: ListView(
            children: <Widget>[
              headerBox,
              _isNew ? Container() : invoiceNumberBox,
              _isNew ? Container() : statusBox,
              _showCartons ? cartonTable : Container(),
              _showCartons
                  ? Divider(
                      color: primaryColor,
                      thickness: 2,
                    )
                  : Container(),
              invoiceTableBox,
              SizedBox(
                height: 10,
              ),
              paymentTypesBox,
              SizedBox(
                height: 10,
              ),
              _isNew
                  ? createBtn
                  : mainModel.isCustomer()
                      ? Container()
                      : Container(
                          child: Column(
                          children: <Widget>[
                            fcsButton(context,
                                getLocalString(context, 'invoice.btn_save'))
                          ],
                        )),
              _isNew
                  ? Container()
                  : fcsButton(context,
                      getLocalString(context, 'invoice.btn_payment_receipt'))
            ],
          ),
        ),
      ),
    );
  }

  _addCustom(CustomDuty customDuty) {
    if (customDuty == null) return;
    setState(() {
      _invoice.customDuties.remove(customDuty);
      _invoice.customDuties.add(customDuty);
    });
  }

  _addShipment(Shipment shipment) {
    if (shipment == null) return;
    shipment.isSelected = true;
    setState(() {
      _invoice.shipments.remove(shipment);
      _invoice.shipments.add(shipment);
    });
  }

  _removeShipment(Shipment shipment) {
    if (shipment == null) return;
    shipment.isSelected = false;
    setState(() {
      _invoice.shipments.remove(shipment);
      _invoice.shipments.add(shipment);
    });
  }

  _removeCustom(CustomDuty customDuty) {
    setState(() {
      _invoice.customDuties.remove(customDuty);
    });
  }

  _save() async {
    var rateModel = Provider.of<ShipmentRateModel>(context, listen: false);
    double amount = _invoice.getNetAmount(rateModel.rate);
    if (_invoice.paymentMethod == null) {
      showMsgDialog(context, "Error", "Payment method required");
      return;
    }
    List<CargoType> cargoTypes = _invoice.getCargoTypes(rateModel.rate);
    if (cargoTypes == null || cargoTypes.length == 0) {
      showMsgDialog(context, "Error", "Expected at least one cargo type");
      return;
    }
    if ((amount ?? 0) <= 0) {
      showMsgDialog(context, "Error", "Expected positive amount");
      return;
    }

    setState(() {
      _isLoading = true;
    });

    try {
      InvoiceModel invoiceModel =
          Provider.of<InvoiceModel>(context, listen: false);

      Invoice invoice = Invoice();
      invoice.cargoTypes = cargoTypes;
      invoice.amount = amount;
      invoice.handlingFee = _invoice.getHandlingFee();
      invoice.cartons = _invoice.cartons.where((c) => c.isChecked).toList();
      invoice.shipments =
          _invoice.shipments.where((s) => s.isSelected).toList();
      invoice.discount = _invoice.discount;
      invoice.deliveryFee = _invoice.deliveryFee;

      invoice.userID = widget.customer.id;
      invoice.fcsShipmentID = widget.fcsShipment.id;
      invoice.invoiceDate = _invoice.invoiceDate;
      invoice.paymentMethod = _invoice.paymentMethod;
      invoice.customDuties = _invoice.customDuties;

      await invoiceModel.createInvoice(invoice);
      Navigator.pop(context, true);
    } catch (e) {
      showMsgDialog(context, "Error", e.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }
}
