import 'package:checker/base/base_screen.dart';
import 'package:checker/db.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'dart:convert';
import 'dart:core';
import 'dart:async';

import 'package:checker/resources.dart';
import 'package:checker/strings.dart';
import 'package:checker/common.dart';
import 'package:checker/consts.dart';
import 'package:checker/network.dart';
import 'package:checker/base/base_state.dart';
import 'package:checker/screens/purchase_success.dart';

/// Экран проведения покупки.
class PurchaseScreen extends BaseScreen {

  PurchaseScreen(helper, app, this.user, this.card) : super(helper, app);

  final String user;
  final String card;

  @override
  State createState() => new PurchaseScreenState<PurchaseScreen>(helper, app, user, card);
}

class PurchaseScreenState<T> extends BaseState<PurchaseScreen> {
  /// Объект, помогающий вручную изменять введенный пользователем текст.
  /// Используется для форматирования введенных пользователем данных
  /// (удаляет запрещенные символы до их отображаения).
  TextEditingController controller = new TextEditingController();

  TextEditingController bonusController = new TextEditingController();

  FocusNode _focusNodeSum = new FocusNode();
  FocusNode _focusNodeBonus = new FocusNode();

  bool isAutomaticallyImplyLeading() => false;

  PurchaseScreenState(SqliteHelper helper, String app, String userString, String card) : super(helper, app) {
    this.user = JSON.decode(userString);
    this.card = card;
  }

  @override
  void initState() {
    loading = true;
    requestAsyncData(user);
    super.initState();
  }

  @override
  Widget build(BuildContext ctx) {
    return getMainWidget();
  }

  bool purchaseInProgress = false;
  Map user;
  String card = '';
  String loyalityType = '';
  String loyalty = '';
  String bonus = '';
  List<Map> coupons = [];

  @override
  Widget getScreenContent() {
    List<Widget> widgetList = [];
    widgetList.add(getValueWithDescription(
        StringsLocalization.buyer(),
        user['first_name'] == null ? '' : user['first_name']
    ));
    widgetList.add(getValueWithDescription(StringsLocalization.card(), card));

    if (app != 'crypto') {
      widgetList.add(getValueWithDescription(StringsLocalization.reward(), loyalty));
    }

    if (bonus.length > 0) {
      widgetList.add(getValueWithDescription(StringsLocalization.bonus(), bonus));
    }

    widgetList.add(getHintLabel());
    widgetList.add(getInputField()); // Нельзя добавить еще одно поле таким же способом

    if (app != 'autobonus') {

      if (this.loyalityType == 'bonus') {
        widgetList.add(getBonusInputField());
      }

      if (this.coupons.length > 0) {
        widgetList.add(getItemTitle(StringsLocalization.selectCoupons()));
        this.coupons.forEach((couponItem) {
          widgetList.add(getItemToggleSwitch(
            couponItem['offer_name'],
            couponItem['coupon_condition'],
            couponItem['isSet'],
              (val) {
              setState(() {
                couponItem['isSet'] = val;
              });
            }
          ));
        });
      }
    }

    widgetList.add(wrapButton(getScreenMargins(36.0), getCompleteButton()));

    widgetList.add(wrapButton(
        getScreenMargins(24.0),
        getScanButton(
            context,
            StringsLocalization.scan(),
            Resources.getPrimaryColor(app)
        )
    ));

    return new Column(children: <Widget>[
      new Expanded(
          child: new ListView(children: widgetList))
    ]);
  }

  getBonusInputField() {

    var bonusTextField = new EnsureVisibleWhenFocused(
      focusNode: _focusNodeBonus,
      child: new TextField(
        focusNode: _focusNodeBonus,
      keyboardType: TextInputType.number,
      decoration: new InputDecoration.collapsed(
        hintText: StringsLocalization.bonusHint(),
        hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)
      ),
      controller: bonusController,
      onSubmitted: (String text) {
        setState(() {
          bonusController.text = text;
        });
      },
      textAlign: TextAlign.center,
    ));

    return new Column(
      children: <Widget>[
        new Container(
          margin: new EdgeInsets.only(
            left: verticalMargin,
            right: verticalMargin,
            top: verticalMargin
          ),
          padding: getInputFieldContainerPadding(),
          decoration: getInputFieldContainerDecoration(),
          child: bonusTextField
        ),
        new Container(
          margin: new EdgeInsets.only(
            top: 5.0
          ),
          child: new Text(
            StringsLocalization.bonusExplanation(),
            textAlign: TextAlign.center,
            overflow: TextOverflow.ellipsis,
            style: new TextStyle(color: greyTextColor, fontSize: 11.0),
          )
        )
      ],
    );
  }

  getScreenMargins(double top) {
    double side = 42.0;
    return new EdgeInsets.only(top: top, left: side, right: side);
  }

  getCompleteButton() {
    return buildRaisedButton(
        StringsLocalization.completePurchase(), () => onPurchaseClick());
  }

  Widget getScanButton(BuildContext context, String title, Color textColor) {
    return new Container(
        height: buttonHeight,
        child: new FlatButton(
            child: new Text(title, style: new TextStyle(color: textColor)),
            onPressed: () => restartScanner()),
        decoration: new BoxDecoration(
            border: new Border.all(
                color: Resources.getButtonColor(app), width: 1.0),
            borderRadius: new BorderRadius.all(new Radius.circular(4.0))));
  }

  @override
  String getTitle() {
    return StringsLocalization.carryingPurchase();
  }

  @override
  getHintString() {
    return StringsLocalization.sum();
  }

  @override
  getTextWidget() {
    // ?? TODO переделать, т.к. позволяет иметь только одно поле ввода на странице
    return new EnsureVisibleWhenFocused(
      focusNode: _focusNodeSum,
      child: new TextField(
        focusNode: _focusNodeSum,
      keyboardType: TextInputType.number,
      decoration: new InputDecoration.collapsed(
          hintText: getHintString(),
          hintStyle: new TextStyle(color: greyTextColor, fontSize: 16.0)),
      controller: controller,
      onSubmitted: (String text) {
        setState(() {
          controller.text = _parseSum(text);
        });
      },
      textAlign: TextAlign.center,
      autofocus: true
    ));
  }

  requestAsyncData(Map user) async {
    bool showBonus = await platform.invokeMethod('showBonus');
    if (await platform.invokeMethod('isOnline')) {
      var response, couponResponse;
      print(user['coupons_url']);
      try {
        var token = await helper.getToken();
        response = await getLoyaltyRequest(user['loyalty_url'], token);
        couponResponse = await getCouponsRequest(
          user['coupons_url'] + '?status=ACTIVE',
          token
        );
      } catch(error) {
        print(error.toString());
      }
      Map loyality = JSON.decode(response.body);
      Map coupons = JSON.decode(couponResponse.body);

      coupons['results'].forEach((couponItem) {
        couponItem['isSet'] = false;
      });
      setState(() {
        loading = false;
        this.coupons = coupons['results'];
        this.loyalityType = loyality['type'];
        setBonuses(loyality, showBonus);
      });
    }
  }

  // TODO: Переделать, если потребуется
  String _cleanupNumber(String text) {
    String tmp = text
        .replaceAll(' ', '')
        .replaceAll('-', '')
        .replaceAll(',', '.')
        .replaceAll('..', '.');

    while (tmp.indexOf('..') != -1) {
      tmp = tmp.replaceAll('..', '.');
    }
    return tmp;
  }

  _parseSum(String input) {
    num sumTotal = 0.0;
    String text = _cleanupNumber(input);

    try {
      sumTotal = num.parse(text);
    } catch (exception) {
      print(exception);
      try {
        int idx = text.indexOf('.');
        String integerPart = text.substring(0, idx);
        String fractionalPart = text.substring(idx + 1, text.length);
        if (fractionalPart.length > 2) {
          fractionalPart = fractionalPart.substring(0, 2);
        }
        return '$integerPart.$fractionalPart';
      } catch (exception) {
        print(exception);
      }
    }
    print(sumTotal.toStringAsFixed(2));
    return sumTotal.toStringAsFixed(2);
  }

  onPurchaseClick() {
    String val = _parseSum(controller.text);
    helper.getCurrency().then((currency) {
      print(currency.toString());
      showDialog(
          context: context,
          child: new AlertDialog(
              title: new Text(StringsLocalization.confirmation()),
              content:
              new Text(
                StringsLocalization.confirmPurchase(val, currency)
              ),
              actions: <Widget>[
                new FlatButton(
                  child: new Text(StringsLocalization.no()),
                  onPressed: () {
                    Navigator.of(context).pop();
                  },
                ),
                new FlatButton(
                  child: new Text(StringsLocalization.yes()),
                  onPressed: () {
                    Navigator.of(context).pop();
                    purchase(val);
                  },
                )
              ]));
    });
  }

  apiErrorAlert(String errorText) {
    showDialog(
      context: context,
      child: new AlertDialog(
        content: new Text(errorText),
        actions: <Widget>[
          new FlatButton(
            child: new Text('Ok'),
            onPressed: () {
              Navigator.of(context).pop();
            },
          )
        ]
      )
    );
  }

  purchase(String sumTotal) async {
    setState(() {
      loading = true;
    });
    if (await platform.invokeMethod('isOnline')) {
      if (!purchaseInProgress) {
        purchaseInProgress = true;

        String token = await helper.getToken();
        var result = await helper.getMerchantID();
        var currency = await helper.getCurrency();
        var couponIds = [];

        this.coupons.forEach((item) {
          if (item['isSet'] == true) couponIds.add(item['id']);
        });

        print(couponIds);

        var body = {
          'doc_id': result,
          'curr_iso_code': currency.toString(),
          'commit': 'true',
          'sum_total': sumTotal,
        };

        if (bonusController.text.length > 0) {
          body['bonus_payment'] = bonusController.text;
        }

        if (couponIds.length > 0) {
          body['coupons'] = couponIds.join(",");
        }

        var purchaseResponse;
        Map purchase;

        try {
          purchaseResponse = await getPurchaseRequest(user['purchases_url'], body, token);
          purchase = JSON.decode(purchaseResponse.body);
        } catch(error) {
          purchaseInProgress = false;
          print(error.toString());
        }

        if (purchase.containsKey('errors')) {
          List<String> errors = purchase['errors'];
          purchaseInProgress = false;
          apiErrorAlert(errors[0]);
        } else {
          var couponsResponse;

          try {
            couponsResponse = await getCouponsRequest(purchase['coupons_url'], token);
            print(couponsResponse.body);
          } catch(error) {
            purchaseInProgress = false;
            print(error.toString());
          }

          Map coupons = JSON.decode(couponsResponse.body);

          new Future.delayed(const Duration(milliseconds: 200), () {
            print('show purchase success!');
            var route = new MaterialPageRoute<String>(builder: (BuildContext context) => new PurchaseSuccessScreen(
              sumTotal,
              user['first_name'] == null ? '' : user['first_name'],
              helper,
              app,
              purchase,
              coupons['results']
            ), fullscreenDialog: true);
            Navigator.of(context).push(route).then((token) {
              Navigator.of(context).pop(token);
            });
          });
        }
      }
    }
  }

  void setBonuses(Map bonuses, bool showBonus) {
    print('kifio ' + this.loyalityType);
    if (bonuses['type'] == 'amount') {
      this.loyalty = '${user['discount']}%';
    } else {
      double loyaltyVal = (double.parse(bonuses['amount_to_bonus'][1]) /
          bonuses['amount_to_bonus'][0]) * 100;
      this.loyalty = '${loyaltyVal.toStringAsFixed(0)}%';
    }

    if (showBonus && (this.loyalityType == 'bonus')) {
      this.bonus = '${user['bonus']}';
    }
    print('kifio ' + this.loyalty);
    print('bonus ' + this.bonus);
  }

  restartScanner() {
    helper.getToken().then((token) {
      Navigator.of(context).pop(token);
    });
  }
}
