$(function () {
  var TYPEOPS = {
    // Every change to our supported JSON logic must be done
    // * in pretix.base.services.checkin
    // * in pretix.base.models.checkin
    // * in pretix.helpers.jsonlogic_boolalg
    // * in checkinrules.js
    // * in libpretixsync
    // * in pretixscan-ios
    'product': {
      'inList': {
        'label': gettext('is one of'),
        'cardinality': 2,
      }
    },
    'variation': {
      'inList': {
        'label': gettext('is one of'),
        'cardinality': 2,
      }
    },
    'gate': {
      'inList': {
        'label': gettext('is one of'),
        'cardinality': 2,
      }
    },
    'datetime': {
      'isBefore': {
        'label': gettext('is before'),
        'cardinality': 2,
      },
      'isAfter': {
        'label': gettext('is after'),
        'cardinality': 2,
      },
    },
    'enum_entry_status': {
      '==': {
        'label': gettext('='),
        'cardinality': 2,
      },
    },
    'int_by_datetime': {
      '<': {
        'label': '<',
        'cardinality': 2,
      },
      '<=': {
        'label': '≤',
        'cardinality': 2,
      },
      '>': {
        'label': '>',
        'cardinality': 2,
      },
      '>=': {
        'label': '≥',
        'cardinality': 2,
      },
      '==': {
        'label': '=',
        'cardinality': 2,
      },
      '!=': {
        'label': '≠',
        'cardinality': 2,
      },
    },
    'int': {
      '<': {
        'label': '<',
        'cardinality': 2,
      },
      '<=': {
        'label': '≤',
        'cardinality': 2,
      },
      '>': {
        'label': '>',
        'cardinality': 2,
      },
      '>=': {
        'label': '≥',
        'cardinality': 2,
      },
      '==': {
        'label': '=',
        'cardinality': 2,
      },
      '!=': {
        'label': '≠',
        'cardinality': 2,
      },
    },
  };
  var VARS = {
    'product': {
      'label': gettext('Product'),
      'type': 'product',
    },
    'variation': {
      'label': gettext('Product variation'),
      'type': 'variation',
    },
    'gate': {
      'label': gettext('Gate'),
      'type': 'gate',
    },
    'now': {
      'label': gettext('Current date and time'),
      'type': 'datetime',
    },
    'now_isoweekday': {
      'label': gettext('Current day of the week (1 = Monday, 7 = Sunday)'),
      'type': 'int',
    },
    'entry_status': {
      'label': gettext('Current entry status'),
      'type': 'enum_entry_status',
    },
    'entries_number': {
      'label': gettext('Number of previous entries'),
      'type': 'int',
    },
    'entries_today': {
      'label': gettext('Number of previous entries since midnight'),
      'type': 'int',
    },
    'entries_since': {
      'label': gettext('Number of previous entries since'),
      'type': 'int_by_datetime',
    },
    'entries_before': {
      'label': gettext('Number of previous entries before'),
      'type': 'int_by_datetime',
    },
    'entries_days': {
      'label': gettext('Number of days with a previous entry'),
      'type': 'int',
    },
    'entries_days_since': {
      'label': gettext('Number of days with a previous entry since'),
      'type': 'int_by_datetime',
    },
    'entries_days_before': {
      'label': gettext('Number of days with a previous entry before'),
      'type': 'int_by_datetime',
    },
    'minutes_since_last_entry': {
      'label': gettext('Minutes since last entry (-1 on first entry)'),
      'type': 'int',
    },
    'minutes_since_first_entry': {
      'label': gettext('Minutes since first entry (-1 on first entry)'),
      'type': 'int',
    },
  };

  var components = {
    CheckinRulesVisualization: CheckinRulesVisualization.default,
  }
  if (typeof CheckinRule !== "undefined") {
    Vue.component('checkin-rule', CheckinRule.default);
    components = {
      CheckinRulesEditor: CheckinRulesEditor.default,
      CheckinRulesVisualization: CheckinRulesVisualization.default,
    }
  }
  var app = new Vue({
    el: '#rules-editor',
    components: components,
    data: function () {
      return {
        rules: {},
        items: [],
        all_products: false,
        limit_products: [],
        TYPEOPS: TYPEOPS,
        VARS: VARS,
        texts: {
          and: gettext('All of the conditions below (AND)'),
          or: gettext('At least one of the conditions below (OR)'),
          date_from: gettext('Event start'),
          date_to: gettext('Event end'),
          date_admission: gettext('Event admission'),
          date_custom: gettext('custom date and time'),
          date_customtime: gettext('custom time'),
          date_tolerance: gettext('Tolerance (minutes)'),
          condition_add: gettext('Add condition'),
          minutes: gettext('minutes'),
          duplicate: gettext('Duplicate'),
          status_present: pgettext('entry_status', 'present'),
          status_absent: pgettext('entry_status', 'absent'),
        },
        hasRules: false,
      };
    },
    computed: {
      missingItems: function () {
        // This computed property contains list of item or variation names that
        // a) Are allowed on the checkin list according to all_products or include_products
        // b) Are not matched by ANY logical branch of the rule.
        // The list will be empty if there is a "catch-all" rule.
        var products_seen = {};
        var variations_seen = {};
        var rules = convert_to_dnf(this.rules);
        var branch_without_product_filter = false;

        if (!rules["or"]) {
          rules = {"or": [rules]}
        }

        for (var part of rules["or"]) {
          if (!part["and"]) {
            part = {"and": [part]}
          }
          var this_branch_without_product_filter = true;
          for (var subpart of part["and"]) {
            if (subpart["inList"]) {
              if (subpart["inList"][0]["var"] === "product" && subpart["inList"][1]) {
                this_branch_without_product_filter = false;
                for (var listentry of subpart["inList"][1]["objectList"]) {
                  products_seen[parseInt(listentry["lookup"][1])] = true
                }
              } else if (subpart["inList"][0]["var"] === "variation" && subpart["inList"][1]) {
                this_branch_without_product_filter = false;
                for (var listentry_ of subpart["inList"][1]["objectList"]) {
                  variations_seen[parseInt(listentry_["lookup"][1])] = true
                }
              }
            }
          }
          if (this_branch_without_product_filter) {
            branch_without_product_filter = true;
            break;
          }
        }
        if (branch_without_product_filter || (!Object.keys(products_seen).length && !Object.keys(variations_seen).length)) {
          // At least one branch with no product filters at all – that's fine.
          return [];
        }

        var missing = [];
        for (var item of this.items) {
          if (products_seen[item.id]) continue;
          if (!this.all_products && !this.limit_products.includes(item.id)) continue;
          if (item.variations.length > 0) {
            for (var variation of item.variations) {
              if (variations_seen[variation.id]) continue;
              missing.push(item.name + " – " + variation.name)
            }
          } else {
            missing.push(item.name)
          }
        }
        return missing;
      }
    },
    created: function () {
      this.rules = JSON.parse($("#id_rules").val());
      if ($("#items").length) {
        this.items = JSON.parse($("#items").html());

        var root = this.$root

        function _update() {
          root.all_products = $("#id_all_products").prop("checked")
          root.limit_products = $("input[name=limit_products]:checked").map(function () {
            return parseInt($(this).val())
          }).toArray()
        }

        $("#id_all_products, input[name=limit_products]").on("change", function () {
          _update();
        })
        _update()
      }
    },
    watch: {
      rules: {
        deep: true,
        handler: function (newval) {
          $("#id_rules").val(JSON.stringify(newval));
        }
      },
    }
  })
});
