

import 'dart:convert';

import 'package:flutter/material.dart';
import '../../../events/eventbus.dart';
import '../../../events/events.dart';
import '../../../generated/l10n.dart';
import '../../../models/product.dart';
import '../../../models/product_option.dart';
import '../../../utils/utils.dart';

import 'options_base.dart';
import 'rules.dart';

class RadioOptions extends OptionsBase {
  RadioOptions({@required Product product, @required int index, @required Map<String, dynamic> selections})
    : super(product: product, index: index, selections: selections);

  @override
  State<StatefulWidget> createState() {
    return new RadioOptionsState();
  }
}

class RadioOptionsState extends OptionsBaseState<RadioOptions> {
  Map<String, dynamic> optionsState = new Map();

  @override
  Widget build(BuildContext context) {

    return new ListView.builder(
      itemCount: 2,
      itemBuilder: (context, index) {
        if (index == 0) {
          return new Container(
            padding: new EdgeInsets.all(10.0),
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.start,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                new Text(
                  S.of(context).radio_option_select_token(product.productAttributes[this.index].name),
                  style: new TextStyle(
                    fontSize: 12.5,
                  ),
                  overflow: TextOverflow.ellipsis,
                ),
                new Text(
                  product.productAttributes[this.index].required ? S.of(context).radio_option_is_required : S.of(context).radio_option_is_optional,
                  style: new TextStyle(
                    fontSize: 10.0,
                    color: new Color(0xFF999999)
                  ),
                  overflow: TextOverflow.ellipsis,
                )
              ],
            ),
          );
        }
        return _getOptionWidget();
      }
    );
  }

  @override
  void initState() {
    super.initState();
    setState(() {
      product = widget.product;
      selections = widget.selections;
      index = widget.index;
    });
    eventBus.on<OnAttributePageChanged>().listen((event) {
      setState(() {
        index = event.index;
      });
    });
  }

  void _onOptionTappedCallback(name, quantity, adjustAmount, int optIndex, ProductOption productOption) {
    Map<String, dynamic> opt = {
      'name': name,
      'quantity': quantity,
      'adjust_amount': adjustAmount
    };
    var cloneSelections = json.decode(json.encode(selections));
    if (product.productAttributes[index].required) {
      cloneSelections[product.productAttributes[index].name.toUpperCase()] = [opt];
    } else {
      if (cloneSelections.containsKey(product.productAttributes[index].name.toUpperCase())
          && Utils.equalsIgnoreCase(cloneSelections[product.productAttributes[index].name.toUpperCase()][0]['name'], name)) {
        cloneSelections.remove(product.productAttributes[index].name.toUpperCase());
      } else {
        cloneSelections[product.productAttributes[index].name.toUpperCase()] = [opt];
      }
    }

    Map<String, dynamic> extraJson = Utils.stringToJson(productOption.extra);
    if (extraJson != null) {
      Map<String, dynamic> exclusiveRule = Rule.getRule(
          extraJson, Rule.RULE_EXCLUSIVE_SELECTION);
      if (exclusiveRule != null) {
        if (_checkOptionIsCheck(productOption.name)) {
          setOptionsStateDisabled(product.productAttributes[index].name, false);
        }
      }
    }

    setState(() {
      selections = cloneSelections;
    });
    eventBus.fire(new OnAttributeSelectionsChanged(selections));
  }

  Widget _getOptionWidget() {
    var row = Wrap(
      children: <Widget>[],
    );

    List<ProductOption> productOptions = product.productAttributes[index].productOptions;

    if (!optionsState.containsKey(product.productAttributes[index].name)) {
      List<Map<String, dynamic>> optionState = [];
      for (var i = 0; i < productOptions.length; i++) {
        optionState.add({'name': product.productAttributes[index].productOptions[i].name, 'disabled': false, 'check': false});
      }
      optionsState[product.productAttributes[index].name] = optionState;
    }

    for (var i = 0; i < productOptions.length; i++) {
      Map<String, dynamic> extraJson = Utils.stringToJson(productOptions[i].extra);
      if (extraJson != null) {
        Map<String, dynamic> exclusiveRule = Rule.getRule(
            extraJson, Rule.RULE_EXCLUSIVE_SELECTION);
        if (exclusiveRule != null) {
          if (_checkOptionIsCheck(productOptions[i].name)) {
            setOptionsStateDisabled(product.productAttributes[index].name, true);
            optionsState[product.productAttributes[index].name][i]['disabled'] = false;
            break;
          }
        }
      }
    }

    List<Map<String, dynamic>> optionState = optionsState[product.productAttributes[index].name];
    for (var i = 0; i < optionState.length; i++) {
      Widget optionWidget = _getOptionRadio(
          product.productAttributes[index].productOptions[i], optionState[i]['disabled'], i);
      row.children.add(optionWidget);
    }
    return row;
  }

  bool _checkOptionIsCheck(String name) {
    if (Utils.selectionsContains(selections, product.productAttributes[index].name, name) != -1) {
      return true;
    }
    return false;
  }

  Widget _getOptionRadio(ProductOption productOption, bool optDisabled, int optIndex) {
    bool disabled = optDisabled;
    bool check = _checkOptionIsCheck(productOption.name);

    Map<String, dynamic> extraJson = Utils.stringToJson(productOption.extra);
//    Utils.jsonPrettyPrint(extraJson);

    double extraAdjustAmount = 0.0;

    if (extraJson != null) {
      var sizeBaseAdjustment = Rule.getRule(extraJson, Rule.RULE_ADJUSTMENT_BASED_ON_SELECTED_FIELD_VALUE);
      if (sizeBaseAdjustment != null) {
        if (sizeBaseAdjustment is List) {
          for (var i = 0; i < (sizeBaseAdjustment as List).length; i++) {
            Map<String, dynamic> sizeBaseAdjustment1 = sizeBaseAdjustment[i];
            List<String> attValues = Utils.getSelectedAttributeValue(selections, sizeBaseAdjustment1[Rule.RULE_KEY_FIELD_KEY]);
            if (attValues.length > 0 && sizeBaseAdjustment1.containsKey(attValues[0])) {
              extraAdjustAmount += sizeBaseAdjustment1[attValues[0]];
            }
          }
        } else {
          List<String> attValues = Utils.getSelectedAttributeValue(selections, sizeBaseAdjustment[Rule.RULE_KEY_FIELD_KEY]);
          if (attValues.length > 0 && sizeBaseAdjustment.containsKey(attValues[0])) {
            extraAdjustAmount += sizeBaseAdjustment[attValues[0]];
          }
        }
      }

      var disabledRule =
      Rule.getRule(extraJson, Rule.RULE_DISABLED_IF_FIELD_EQUALS_TO);
      if (disabledRule != null) {
        if (disabledRule is List) {
          for (var i = 0; i < (disabledRule as List).length; i++) {
            Map<String, dynamic> disabledRule1 = disabledRule[i];
            List<String> attValues = Utils.getSelectedAttributeValue(
                selections, disabledRule1[Rule.RULE_KEY_FIELD_KEY]);
            if (attValues.length > 0 &&
                disabledRule1.containsKey(attValues[0])) {
              disabled = true;
            }
            if (attValues.length > 0) {
              for (String s in attValues) {
                if (disabledRule1.containsKey(s) && disabledRule1[s]) {
                  disabled = true;
                  break;
                }
              }
            }
            if (disabled) {
              break;
            }
          }
        } else {
          List<String> attValues = Utils.getSelectedAttributeValue(
              selections, disabledRule[Rule.RULE_KEY_FIELD_KEY]);
          if (attValues.length > 0) {
            for (String s in attValues) {
              if (disabledRule.containsKey(s) && disabledRule[s]) {
                disabled = true;
                break;
              }
            }
          }
        }
      }
    }

    return new GestureDetector(
      child: new Container(
        width: 100.0,
        height: 70.0,
        decoration: BoxDecoration(
          color: disabled ? disabledBackgroundColor : (check ? selectedBackgroundColor : deselectBackgroundColor),
          shape: BoxShape.rectangle,
          border:  new Border.all(
            color: check ? selectedBorderColor : deselectBorderColor,
            width: 1.0,
          ),
          borderRadius: BorderRadius.all(Radius.circular(10.0)),
        ),
        padding: new EdgeInsets.all(4.0),
        margin: new EdgeInsets.all(10.0).copyWith(right: 0.0),
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Text(
              productOption.name,
              style: new TextStyle(
                fontSize: 14.0,
                color: check ? selectedTextColor : deselectTextColor,
              ),
              maxLines: 2,
              softWrap: true,
              overflow: TextOverflow.ellipsis,
            ),
            new Text(
              (productOption.adjustAmount + extraAdjustAmount) > 0 ? '+${(productOption.adjustAmount + extraAdjustAmount).toStringAsFixed(2)}' : '',
              style: new TextStyle(
                fontSize: 11.0,
                color: check ? selectedTextColor : new Color(0xFFABABAB),
              ),
              overflow: TextOverflow.ellipsis,
            )
          ],
        ),
      ),
      onTap: () => disabled ? null : _onOptionTappedCallback(
          productOption.name, 0, productOption.adjustAmount + extraAdjustAmount, optIndex, productOption),
    );
  }

  void setOptionsStateDisabled(String attrName, bool disabled) {
    if (optionsState.containsKey(attrName)) {
      Map<String, dynamic> optionState = optionsState[attrName];
      for (var i = 0; i < optionState.length; i++) {
        optionState[i]['disabled'] = disabled;
      }
    }
  }
}