import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/carton.dart';
import 'package:fcs/domain/entities/shipment.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/pages/carton/model/carton_model.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/shipment/model/shipment_model.dart';
import 'package:fcs/pages/shipment/shipment_pack.dart';
import 'package:fcs/pages/widgets/defalut_delivery_address.dart';
import 'package:fcs/pages/widgets/display_text.dart';
import 'package:fcs/pages/widgets/fcs_id_icon.dart';
import 'package:fcs/pages/widgets/local_button.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_radio_buttons.dart';
import 'package:fcs/pages/widgets/local_text.dart';
import 'package:fcs/pages/widgets/local_title.dart';
import 'package:fcs/pages/widgets/multi_img_controller.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:intl/intl.dart';
import 'package:provider/provider.dart';
import 'package:url_launcher/url_launcher.dart';

import 'box_row.dart';
import 'shipment_assign.dart';
import 'shipment_confirm.dart';
import 'shipment_editor.dart';
import 'widgets.dart';

class ShipmentInfo extends StatefulWidget {
  final bool isCustomer;
  final Shipment shipment;
  ShipmentInfo({this.shipment, this.isCustomer});

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

class _ShipmentInfoState extends State<ShipmentInfo> {
  var dateFormatter = new DateFormat('dd MMM yyyy');
  final numberFormatter = new NumberFormat("#,###");
  MultiImgController multiImgController = MultiImgController();
  var timeFormatter = new DateFormat('jm');

  TextEditingController _addressEditingController = new TextEditingController();
  TextEditingController _fromTimeEditingController =
      new TextEditingController();
  TextEditingController _toTimeEditingController = new TextEditingController();
  TextEditingController _noOfPackageEditingController =
      new TextEditingController();
  TextEditingController _weightEditingController = new TextEditingController();
  TextEditingController _recipientNameEditingController =
      new TextEditingController();
  TextEditingController _recipientPhoneEditingController =
      new TextEditingController();
  TextEditingController _recipientAddressEditingController =
      new TextEditingController();
  TextEditingController _pickupDate = new TextEditingController();
  TextEditingController _handlingFeeController = new TextEditingController();

  Shipment _shipment;
  bool _isLoading = false;
  bool _isCustomer;
  var now = new DateTime.now();

  @override
  void initState() {
    super.initState();
    _shipment = widget.shipment;
    _isCustomer = widget.isCustomer;
    _loadCartons(_shipment.id);

    _addressEditingController.text = _shipment.address;
    _fromTimeEditingController.text = _shipment.pickupTimeStart;
    _toTimeEditingController.text = _shipment.pickupTimeEnd;
    _noOfPackageEditingController.text = _shipment.numberOfPackage.toString();
    _weightEditingController.text = _shipment.weight.toString();
    _pickupDate.text = dateFormatter.format(_shipment.pickupDate ?? now);
  }

  _loadCartons(String shipmentID) async {
    CartonModel cartonModel = Provider.of<CartonModel>(context, listen: false);
    var cartons = await cartonModel.getCartons(shipmentID);
    setState(() {
      _shipment.boxes = cartons;
    });
  }

  _loadShipment(String id) async {
    ShipmentModel shipmentModel =
        Provider.of<ShipmentModel>(context, listen: false);
    Shipment s = await shipmentModel.getShipment(id);
    s.boxes = _shipment.boxes;
    setState(() {
      _shipment = s;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    MainModel mainModel = Provider.of<MainModel>(context);
    ShipmentModel pickupModel = Provider.of<ShipmentModel>(context);
    bool isLocalPickup = _shipment.shipmentType == shipment_local_pickup;
    bool isCourierPickup = _shipment.shipmentType == shipment_courier_pickup;
    bool isLocalDropoff = _shipment.shipmentType == shipment_local_dropoff;
    bool isCourierDropoff = _shipment.shipmentType == shipment_courier_dropoff;
    bool isEditable = widget.isCustomer
        ? (_shipment.isPending || _shipment.isAssigned)
        : (_shipment.isPending || _shipment.isAssigned || _shipment.isPickuped);
    bool canCancel =
        _shipment.isPending || _shipment.isConfirmed || _shipment.isAssigned;

    final popupMenu = LocalPopupMenuButton(
      popmenus: [
        LocalPopupMenu(
          enabled: _shipment.isPending && isLocalPickup,
          id: 1,
          textKey: "shipment.assign.for.pickup",
        ),
        LocalPopupMenu(
          enabled:
              (_shipment.isPickuped && isLocalPickup) || _shipment.isReceived,
          id: 3,
          textKey: "shipment.pack.menuitem",
        ),
        LocalPopupMenu(
          enabled: _shipment.isPending && (isCourierPickup || isCourierDropoff),
          id: 4,
          textKey: "shipment.confirm.menuitem",
        ),
        LocalPopupMenu(
          enabled: canCancel,
          id: 2,
          textKey: "btn.cancel",
        ),
      ],
      selectable: false,
      buttonIcon: Icons.more_vert,
      popupMenuCallback: (p) => p.id == 1
          ? _gotoAssign()
          : p.id == 2
              ? _cancel()
              : p.id == 3 ? _gotoPack() : p.id == 4 ? _gotoConfirm() : null,
    );
    final popupMenuCustomer = LocalPopupMenuButton(
      popmenus: [
        LocalPopupMenu(
          enabled: canCancel,
          id: 2,
          textKey: "btn.cancel",
        ),
      ],
      selectable: false,
      buttonIcon: Icons.more_vert,
      popupMenuCallback: (p) => p.id == 2 ? _cancel() : null,
    );
    final shipmentNumberBox = getShipmentNumberStatus(context, _shipment);

    final fromTimeBox = DisplayText(
      labelTextKey: 'shipment.from',
      iconData: Icons.timer,
      text: _shipment.pickupTimeStart,
    );
    final toTimeBox = DisplayText(
      labelTextKey: 'shipment.to',
      iconData: Icons.timer_off,
      text: _shipment.pickupTimeEnd,
    );

    final pickupDateBox = DisplayText(
      labelTextKey: "shipment.date",
      iconData: Icons.date_range,
      text: dateFormatter.format(_shipment.pickupDate),
    );
    var localDropoffAddressBox = Row(children: [
      FcsIDIcon(),
      Expanded(
        child: DisplayText(
          text: mainModel.setting.usaAddress,
        ),
      )
    ]);
    final curierDropoffAddress = Padding(
        padding: EdgeInsets.all(8),
        child: FloatingActionButton.extended(
          onPressed: _openCourierWebsite,
          icon: Icon(Icons.open_in_new, color: primaryColor),
          label: Text(
            'Visit courier website \nfor nearest drop-off',
            style: TextStyle(fontSize: 16, color: primaryColor),
          ),
          backgroundColor: Colors.white,
        ));
    final pickupAddressBox = DefaultDeliveryAddress(
      deliveryAddress: _shipment.pickupAddress,
      iconData: Icons.location_on,
      labelKey: "shipment.location",
    );
    var usersBox = DisplayText(
        labelTextKey: "shipment.staff",
        text: _shipment.pickupUserName,
        iconData: MaterialCommunityIcons.worker);
    var handlingFeeBox = DisplayText(
        labelTextKey: "shipment.handling.fee",
        text: (_shipment.handlingFee ?? 0).toString(),
        iconData: FontAwesome.truck);

    final assignCompleteBtn = LocalButton(
      textKey: "shipment.assign.complete.btn",
      callBack: _completeAssign,
    );
    final completePickupBtn = LocalButton(
      textKey: "shipment.pickup.complete.btn",
      callBack: _pickup,
    );
    final completePackBtn = LocalButton(
      textKey: "shipment.pack.complete.btn",
      callBack: _pack,
    );
    final confirmCompleteBtn = LocalButton(
      textKey: "shipment.confirm.complete.btn",
      callBack: _confirm,
    );

    final fcsShipmentNumberBox = DisplayText(
      text: _shipment.fcsShipmentNumber,
      labelTextKey: "FCSshipment.number",
      iconData: Ionicons.ios_airplane,
    );
    final completeReceiveBtn = LocalButton(
      textKey: "shipment.receive.complete.btn",
      callBack: _receive,
    );

    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(),
            ),
            shadowColor: Colors.transparent,
            backgroundColor: Colors.white,
            title: LocalText(
              context,
              "shipment.info",
              fontSize: 20,
              color: primaryColor,
            ),
            actions: <Widget>[
              IconButton(
                icon: Icon(Icons.edit,
                    color: isEditable ? primaryColor : Colors.grey),
                onPressed: isEditable ? _edit : null,
              ),
              widget.isCustomer ? popupMenuCustomer : popupMenu,
            ]),
        body: Padding(
          padding: const EdgeInsets.all(10.0),
          child: ListView(
            children: <Widget>[
              shipmentNumberBox,
              LocalTitle(textKey: "shipment.type"),
              LocalRadioButtons(
                readOnly: true,
                values: pickupModel.shipmentTypes,
                selectedValue: _shipment.shipmentType,
              ),
              ...(isLocalDropoff
                  ? [
                      LocalTitle(textKey: "shipment.location.dropoff"),
                      localDropoffAddressBox
                    ]
                  : []),
              ...(isCourierDropoff
                  ? [
                      LocalTitle(textKey: "shipment.courier.dropoff"),
                      curierDropoffAddress
                    ]
                  : []),
              ...(isCourierPickup || isLocalPickup
                  ? [
                      LocalTitle(textKey: "shipment.location"),
                      pickupAddressBox,
                      LocalTitle(textKey: "shipment.date.time"),
                      pickupDateBox,
                      fromTimeBox,
                      toTimeBox,
                    ]
                  : []),
              LocalTitle(
                textKey: "boxes.name",
                trailing: Text(
                    "${_shipment.totalCount} Cartons - ${_shipment.totalWeight} lb"),
              ),
              Column(
                children: getBoxList(context, _shipment.boxes),
              ),
              !_isCustomer ? fcsShipmentNumberBox : Container(),
              ...(!_shipment.isPending
                  ? [
                      handlingFeeBox,
                    ]
                  : []),
              ...(isLocalPickup
                  ? [
                      LocalTitle(textKey: "shipment.assign.for.pickup"),
                      usersBox,
                    ]
                  : []),
              ...(isLocalPickup && !_isCustomer
                  ? [
                      _shipment.isPending ? assignCompleteBtn : Container(),
                      _shipment.isAssigned ? completePickupBtn : Container(),
                      _shipment.isPickuped ? completePackBtn : Container(),
                    ]
                  : []),
              ...((isCourierPickup || isCourierDropoff) && !_isCustomer
                  ? [
                      _shipment.isPending ? confirmCompleteBtn : Container(),
                      _shipment.isConfirmed ? completeReceiveBtn : Container(),
                      _shipment.isReceived ? completePackBtn : Container(),
                    ]
                  : []),
              ...((isLocalDropoff) && !_isCustomer
                  ? [
                      _shipment.isPending ? completeReceiveBtn : Container(),
                      _shipment.isReceived ? completePackBtn : Container(),
                    ]
                  : []),
            ],
          ),
        ),
      ),
    );
  }

  List<Widget> getBoxList(BuildContext context, List<Carton> boxes) {
    if (boxes == null) return [];
    return boxes.asMap().entries.map((_box) {
      return Row(
        children: [
          Expanded(child: BoxRow(box: _box.value)),
        ],
      );
    }).toList();
  }

  _edit() async {
    bool updated = await Navigator.push<bool>(
      context,
      CupertinoPageRoute(
          builder: (context) => ShipmentEditor(
                shipment: _shipment,
              )),
    );
    if (updated ?? false) {
      await _loadShipment(_shipment.id);
      await _loadCartons(_shipment.id);
    }
  }

  _cancel() {
    showConfirmDialog(context, "shipment.cancel.confirm", () {
      _cancelShipment();
    });
  }

  _cancelShipment() async {
    setState(() {
      _isLoading = true;
    });
    try {
      ShipmentModel shipmentModel =
          Provider.of<ShipmentModel>(context, listen: false);
      await shipmentModel.cancelShipment(_shipment);
      Navigator.pop(context, true);
    } catch (e) {
      showMsgDialog(context, "Error", e.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  _openCourierWebsite() {
    MainModel mainModel = Provider.of<MainModel>(context, listen: false);
    launch("${mainModel.setting.courierWebsite}");
  }

  _gotoAssign() async {
    bool assigned = await Navigator.push<bool>(
      context,
      CupertinoPageRoute(
          builder: (context) => ShipmentAssign(
                shipment: _shipment,
              )),
    );
    if (assigned ?? false) {
      await _loadShipment(_shipment.id);
    }
  }

  _completeAssign() {
    showConfirmDialog(context, "shipment.assign.complete.confirm", () {
      _completeAssignShipment();
    });
  }

  _completeAssignShipment() async {
    setState(() {
      _isLoading = true;
    });
    try {
      ShipmentModel shipmentModel =
          Provider.of<ShipmentModel>(context, listen: false);
      await shipmentModel.completeAssignShipment(_shipment);
      Navigator.pop(context, true);
    } catch (e) {
      showMsgDialog(context, "Error", e.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  _pickup() {
    showConfirmDialog(context, "shipment.pickup.complete.confirm", () {
      _pickupShipment();
    });
  }

  _pickupShipment() async {
    setState(() {
      _isLoading = true;
    });
    try {
      ShipmentModel shipmentModel =
          Provider.of<ShipmentModel>(context, listen: false);
      await shipmentModel.completePickupShipment(_shipment);
      Navigator.pop(context, true);
    } catch (e) {
      showMsgDialog(context, "Error", e.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  _gotoPack() async {
    bool assigned = await Navigator.push<bool>(
      context,
      CupertinoPageRoute(
          builder: (context) => ShipmentPack(
                shipment: _shipment,
              )),
    );
    if (assigned ?? false) {
      await _loadShipment(_shipment.id);
      await _loadCartons(_shipment.id);
    }
  }

  _pack() {
    showConfirmDialog(context, "shipment.pack.complete.confirm", () {
      _packShipment();
    });
  }

  _packShipment() async {
    setState(() {
      _isLoading = true;
    });
    try {
      ShipmentModel shipmentModel =
          Provider.of<ShipmentModel>(context, listen: false);
      await shipmentModel.completePackShipment(_shipment);
      Navigator.pop(context, true);
    } catch (e) {
      showMsgDialog(context, "Error", e.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  _gotoConfirm() async {
    bool assigned = await Navigator.push<bool>(
      context,
      CupertinoPageRoute(
          builder: (context) => ShipmentConfirm(
                shipment: _shipment,
              )),
    );
    if (assigned ?? false) {
      await _loadShipment(_shipment.id);
    }
  }

  _confirm() {
    showConfirmDialog(context, "shipment.confirm.complete.confirm", () {
      _confirmShipment();
    });
  }

  _confirmShipment() async {
    setState(() {
      _isLoading = true;
    });
    try {
      ShipmentModel shipmentModel =
          Provider.of<ShipmentModel>(context, listen: false);
      await shipmentModel.completeConfirmShipment(_shipment);
      Navigator.pop(context, true);
    } catch (e) {
      showMsgDialog(context, "Error", e.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }

  _receive() {
    showConfirmDialog(context, "shipment.receive.complete.confirm", () {
      _receiveShipment();
    });
  }

  _receiveShipment() async {
    setState(() {
      _isLoading = true;
    });
    try {
      ShipmentModel shipmentModel =
          Provider.of<ShipmentModel>(context, listen: false);
      await shipmentModel.completeReceiveShipment(_shipment);
      Navigator.pop(context, true);
    } catch (e) {
      showMsgDialog(context, "Error", e.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }
}
