import 'package:fcs/domain/constants.dart';
import 'package:fcs/domain/entities/carton.dart';
import 'package:fcs/domain/entities/cargo_type.dart';
import 'package:fcs/domain/entities/fcs_shipment.dart';
import 'package:fcs/domain/entities/package.dart';
import 'package:fcs/domain/entities/user.dart';
import 'package:fcs/domain/vo/delivery_address.dart';
import 'package:fcs/helpers/theme.dart';
import 'package:fcs/localization/app_translations.dart';
import 'package:fcs/pages/carton/carton_cargo_table.dart';
import 'package:fcs/pages/carton/carton_mix_table.dart';
import 'package:fcs/pages/carton/carton_package_table.dart';
import 'package:fcs/pages/delivery_address/delivery_address_row.dart';
import 'package:fcs/pages/delivery_address/model/delivery_address_model.dart';
import 'package:fcs/pages/fcs_shipment/model/fcs_shipment_model.dart';
import 'package:fcs/pages/main/model/language_model.dart';
import 'package:fcs/pages/main/model/main_model.dart';
import 'package:fcs/pages/main/util.dart';
import 'package:fcs/pages/package/model/package_model.dart';
import 'package:fcs/pages/rates/model/shipment_rate_model.dart';
import 'package:fcs/pages/user_search/user_serach.dart';
import 'package:fcs/pages/widgets/bottom_up_page_route.dart';
import 'package:fcs/pages/widgets/defalut_delivery_address.dart';
import 'package:fcs/pages/widgets/delivery_address_selection.dart';
import 'package:fcs/pages/widgets/display_text.dart';
import 'package:fcs/pages/widgets/fcs_id_icon.dart';
import 'package:fcs/pages/widgets/length_picker.dart';
import 'package:fcs/pages/widgets/local_button.dart';
import 'package:fcs/pages/widgets/local_dropdown.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/my_data_table.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:provider/provider.dart';
import 'cargo_type_editor.dart';
import 'model/carton_model.dart';
import 'widgets.dart';

class CartonEditor extends StatefulWidget {
  final Carton box;
  CartonEditor({this.box});

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

class _CartonEditorState extends State<CartonEditor> {
  TextEditingController _widthController = new TextEditingController();
  TextEditingController _heightController = new TextEditingController();
  TextEditingController _lengthController = new TextEditingController();

  Carton _carton;
  bool _isLoading = false;
  bool _isNew;
  DeliveryAddress _deliveryAddress = new DeliveryAddress();
  User _user;
  String _selectedCartonType;
  double volumetricRatio = 0;
  double shipmentWeight = 0;
  FcsShipment _fcsShipment;
  List<FcsShipment> _fcsShipments;
  Carton _mixCarton;
  List<Carton> _mixCartons;

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

    //for shipment weight
    volumetricRatio = Provider.of<ShipmentRateModel>(context, listen: false)
        .rate
        .volumetricRatio;
    _lengthController.addListener(_calShipmentWeight);
    _widthController.addListener(_calShipmentWeight);
    _heightController.addListener(_calShipmentWeight);

    if (widget.box != null) {
      _carton = widget.box;
      _deliveryAddress = _carton.deliveryAddress;
      _widthController.text = _carton.width.toString();
      _heightController.text = _carton.height.toString();
      _lengthController.text = _carton.length.toString();
      _selectedCartonType = _carton.cartonType;
      _isNew = false;
      _user = User(fcsID: _carton.fcsID, name: _carton.userName);
      _loadPackages();
    } else {
      _carton = Carton(
        cargoTypes: [],
        packages: [],
      );
      _lengthController.text = "12";
      _widthController.text = "12";
      _heightController.text = "12";
      _isNew = true;
      _selectedCartonType = carton_from_packages;
      _loadFcsShipments();
    }
  }

  _loadFcsShipments() async {
    FcsShipmentModel fcsShipmentModel =
        Provider.of<FcsShipmentModel>(context, listen: false);
    var fcsShipments = await fcsShipmentModel.getActiveFcsShipments();
    var fcsShipment = fcsShipments
        .firstWhere((e) => e.id == _carton.fcsShipmentID, orElse: () => null);
    setState(() {
      _fcsShipments = fcsShipments;
      _fcsShipment = fcsShipment;
    });
  }

  _loadPackages() async {
    if (_user == null) return;
    PackageModel packageModel =
        Provider.of<PackageModel>(context, listen: false);
    List<Package> packages = await packageModel.getPackages(
        _user.id, [package_processed_status, package_packed_status]);
    if (_isNew) {
      String prevCompare;
      packages.forEach((p) {
        String compare = (p.deliveryAddress?.fullName ?? "") +
            (p.deliveryAddress?.phoneNumber ?? "");
        if (prevCompare != null && compare == prevCompare) {
          p.isChecked = true;
        } else {
          p.isChecked = false;
        }
        if (prevCompare == null) {
          p.isChecked = true;
          prevCompare = compare;
        }
      });
    } else {
      packages.forEach((p) {
        if (_carton.packages.contains(p)) {
          p.isChecked = _carton.packages.firstWhere((cp) => cp == p).isChecked;
        } else {
          p.isChecked = false;
        }
      });
    }

    setState(() {
      _carton.packages = packages;
    });
    _populateDeliveryAddress();
  }

  _populateDeliveryAddress() {
    if (_carton.packages == null) return;
    var d = _carton.packages
        .firstWhere((p) => p.isChecked && p.deliveryAddress != null,
            orElse: () => null)
        ?.deliveryAddress;
    setState(() {
      _deliveryAddress = d;
    });
  }

  _loadMixCartons() async {
    if (_fcsShipment == null || _fcsShipment.id == null) return;
    if (_selectedCartonType != carton_small_bag) return;

    CartonModel cartonModel = Provider.of<CartonModel>(context, listen: false);
    List<Carton> cartons =
        await cartonModel.getMixCartonsByFcsShipment(_fcsShipment.id);
    setState(() {
      _mixCartons = cartons;
    });
  }

  _calShipmentWeight() {
    double l = double.parse(_lengthController.text, (s) => 0);
    double w = double.parse(_widthController.text, (s) => 0);
    double h = double.parse(_heightController.text, (s) => 0);
    setState(() {
      shipmentWeight = l * w * h / volumetricRatio;
    });
  }

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

  @override
  Widget build(BuildContext context) {
    var boxModel = Provider.of<CartonModel>(context);
    bool isMixBox = _selectedCartonType == carton_mix_box;
    bool isSmallBag = _selectedCartonType == carton_small_bag;
    final shipmentBox = DisplayText(
      text: _carton.fcsShipmentNumber,
      labelTextKey: "box.fcs_shipment_num",
      iconData: Ionicons.ios_airplane,
    );
    final mixCartonNumberBox = DisplayText(
      text: _carton.mixCartonNumber,
      labelTextKey: "box.mix.carton",
      iconData: MaterialCommunityIcons.package,
    );
    var fcsShipmentsBox = LocalDropdown<FcsShipment>(
      callback: (v) {
        setState(() {
          _fcsShipment = v;
        });
        _loadMixCartons();
      },
      labelKey: "shipment.pack.fcs.shipment",
      iconData: Ionicons.ios_airplane,
      display: (u) => u.shipmentNumber,
      selectedValue: _fcsShipment,
      values: _fcsShipments,
    );

    var mixCartonsBox = LocalDropdown<Carton>(
      callback: (v) {
        setState(() {
          _mixCarton = v;
        });
      },
      labelKey: "box.mix.carton",
      iconData: MaterialCommunityIcons.package,
      display: (u) => u.cartonNumber,
      selectedValue: _mixCarton,
      values: _mixCartons,
    );

    final fcsIDBox = Row(
      children: <Widget>[
        Expanded(
            child: DisplayText(
          text: _user?.fcsID ?? "",
          labelTextKey: "box.fcs.id",
          icon: FcsIDIcon(),
        )),
        _isNew
            ? IconButton(
                icon: Icon(Icons.search, color: primaryColor),
                onPressed: () => searchUser(context, callbackUserSelect: (u) {
                      setState(() {
                        this._user = u;
                        _loadPackages();
                      });
                    }))
            : Container(),
      ],
    );

    final namebox = DisplayText(
      text: _user?.name ?? "",
      labelTextKey: "box.name",
      iconData: Icons.person,
    );

    final lengthBox = LengthPicker(
      controller: _lengthController,
      lableKey: "box.length",
    );
    final widthBox = LengthPicker(
      controller: _widthController,
      lableKey: "box.width",
    );
    final heightBox = LengthPicker(
      controller: _heightController,
      lableKey: "box.height",
    );

    final dimBox = Row(
      mainAxisAlignment: MainAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.only(right: 8.0),
          child: Icon(FontAwesome.arrow_circle_right, color: primaryColor),
        ),
        SizedBox(child: lengthBox, width: 80),
        SizedBox(child: widthBox, width: 80),
        SizedBox(child: heightBox, width: 80),
      ],
    );

    final shipmentWeightBox = DisplayText(
      text: shipmentWeight != null ? shipmentWeight.toStringAsFixed(0) : "",
      labelTextKey: "box.shipment_weight",
      iconData: MaterialCommunityIcons.weight,
    );

    final createBtn = LocalButton(
      textKey: "box.create.btn",
      callBack: _save,
    );

    final saveBtn = LocalButton(
      textKey: "box.cargo.save.btn",
      callBack: _save,
    );

    final cartonTypeBox = LocalRadioButtons(
        readOnly: !_isNew,
        values: boxModel.cartonTypes,
        selectedValue: _selectedCartonType,
        callback: (v) {
          setState(() {
            _selectedCartonType = v;
          });
        });

    final cargoTableTitleBox = LocalTitle(
      textKey: "box.cargo.type",
      trailing: IconButton(
          icon: Icon(
            Icons.add_circle,
            color: primaryColor,
          ),
          onPressed: () async {
            CargoType cargo = await Navigator.push<CargoType>(context,
                CupertinoPageRoute(builder: (context) => CargoTypeEditor()));
            _addCargo(cargo);
          }),
    );

    final cargoTableBox = CargoTable(
      cargoTypes: _carton.cargoTypes,
      onAdd: (c) => _addCargo(c),
      onRemove: (c) => _removeCargo(c),
    );

    return LocalProgress(
      inAsyncCall: _isLoading,
      child: Scaffold(
        appBar: AppBar(
          centerTitle: true,
          leading: new IconButton(
            icon: new Icon(CupertinoIcons.back, color: primaryColor, size: 30),
            onPressed: () => Navigator.of(context).pop(),
          ),
          shadowColor: Colors.transparent,
          backgroundColor: Colors.white,
          title: _isNew
              ? LocalText(
                  context,
                  "boxes.create.title",
                  fontSize: 20,
                  color: primaryColor,
                )
              : LocalText(
                  context,
                  "box.edit.title",
                  fontSize: 20,
                  color: primaryColor,
                ),
        ),
        body: Padding(
          padding: const EdgeInsets.all(8.0),
          child: ListView(
            shrinkWrap: true,
            children: [
              _isNew
                  ? Container()
                  : Center(child: getCartonNumberStatus(context, _carton)),
              LocalTitle(textKey: "box.type.title"),
              cartonTypeBox,
              LocalTitle(textKey: "box.shipment_info"),
              _isNew ? fcsShipmentsBox : shipmentBox,
              isSmallBag
                  ? _isNew ? mixCartonsBox : mixCartonNumberBox
                  : Container(),
              ...(isMixBox
                  ? [
                      // CartonMixTable(
                      //   cartons: _carton.cartons,
                      //   onSelect: (c, check) {
                      //     setState(() {
                      //       c.isChecked = check;
                      //     });
                      //   },
                      // )
                    ]
                  : [
                      fcsIDBox,
                      namebox,
                      CartonPackageTable(
                        packages: _carton.packages,
                        onSelect: (p, checked) {
                          if (checked &&
                              _deliveryAddress != null &&
                              p.deliveryAddress?.id != _deliveryAddress.id) {
                            return;
                          }
                          setState(() {
                            p.isChecked = checked;
                          });
                          _populateDeliveryAddress();
                        },
                      ),
                      cargoTableTitleBox,
                      cargoTableBox,
                      isSmallBag
                          ? Container()
                          : LocalTitle(textKey: "box.dimension"),
                      isSmallBag ? Container() : dimBox,
                      isSmallBag ? Container() : shipmentWeightBox,
                      LocalTitle(textKey: "box.delivery_address"),
                      DefaultDeliveryAddress(
                        deliveryAddress: _deliveryAddress,
                        labelKey: "box.delivery_address",
                      ),
                    ]),
              _isNew ? createBtn : saveBtn,
              SizedBox(
                height: 20,
              ),
            ],
          ),
        ),
      ),
    );
  }

  List<Widget> getAddressList(
      BuildContext context, List<DeliveryAddress> addresses) {
    return addresses.asMap().entries.map((s) {
      return InkWell(
        onTap: () {},
        child: DeliveryAddressRow(deliveryAddress: s.value),
      );
    }).toList();
  }

  _addCargo(CargoType cargo) {
    if (cargo == null) return;
    setState(() {
      _carton.cargoTypes.remove(cargo);
      _carton.cargoTypes.add(cargo);
    });
  }

  _removeCargo(CargoType cargo) {
    setState(() {
      _carton.cargoTypes.remove(cargo);
    });
  }

  _save() async {
    bool isFromShipment = _selectedCartonType == carton_from_shipments;
    bool isSmallBag = _selectedCartonType == carton_small_bag;
    if (_user == null && (isFromShipment || isSmallBag)) {
      showMsgDialog(context, "Error", "Please select customer");
      return;
    }
    if (_fcsShipment == null && _isNew) {
      showMsgDialog(context, "Error", "Please select FCS shipment");
      return;
    }
    if ((_carton.cargoTypes?.length ?? 0) == 0 &&
        (isFromShipment || isSmallBag)) {
      showMsgDialog(context, "Error", "Expect at least one cargo type");
      return;
    }
    double l = double.parse(_lengthController.text, (s) => 0);
    double w = double.parse(_widthController.text, (s) => 0);
    double h = double.parse(_heightController.text, (s) => 0);
    if ((l <= 0 || w <= 0 || h <= 0) && isFromShipment) {
      showMsgDialog(context, "Error", "Invalid dimension");
      return;
    }
    if (_deliveryAddress == null && (isFromShipment || isSmallBag)) {
      showMsgDialog(context, "Error", "Invalid delivery address");
      return;
    }
    if (isSmallBag && _mixCarton == null && _isNew) {
      showMsgDialog(context, "Error", "Invalid mix carton");
      return;
    }

    Carton carton = Carton();
    carton.id = _carton.id;
    carton.cartonType = _selectedCartonType;
    carton.fcsShipmentID = _isNew ? _fcsShipment.id : _carton.fcsShipmentID;
    carton.userID = _user?.id;
    carton.cargoTypes = _carton.cargoTypes;
    carton.packages = _carton.packages.where((e) => e.isChecked).toList();
    carton.mixCartonID = _mixCarton?.id;
    carton.length = l;
    carton.width = w;
    carton.height = h;
    carton.deliveryAddress = _deliveryAddress;
    setState(() {
      _isLoading = true;
    });
    try {
      CartonModel cartonModel =
          Provider.of<CartonModel>(context, listen: false);
      if (_isNew) {
        await cartonModel.createCarton(carton);
      } else {
        await cartonModel.updateCarton(carton);
      }
      Navigator.pop(context, true);
    } catch (e) {
      showMsgDialog(context, "Error", e.toString());
    } finally {
      setState(() {
        _isLoading = false;
      });
    }
  }
}
