import EmberObject from "@ember/object";
import { buildProperties, mapped, present } from "../lib/wizard-json";
import { listProperties, snakeCase } from "../lib/wizard";
import wizardSchema from "../lib/wizard-schema";
import { Promise } from "rsvp";
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseComputed from "discourse-common/utils/decorators";

const GUEST_GROUP_ID = -1;

const CustomWizardAdmin = EmberObject.extend({
  @discourseComputed("permitted.@each.output")
  allowGuests(permitted) {
    return (
      permitted &&
      permitted.filter((p) => p.output && p.output.includes(GUEST_GROUP_ID))
        .length
    );
  },

  save(opts) {
    return new Promise((resolve, reject) => {
      let wizard = this.buildJson(this, "wizard");

      if (wizard.error) {
        reject(wizard);
      }

      let data = {
        wizard,
      };

      if (opts.create) {
        data.create = true;
      }

      ajax(`/admin/wizards/wizard/${wizard.id}`, {
        type: "PUT",
        contentType: "application/json",
        data: JSON.stringify(data),
      }).then((result) => {
        if (result.backend_validation_error) {
          reject(result);
        } else {
          resolve(result);
        }
      });
    });
  },

  buildJson(object, type, result = {}) {
    let objectType = object.type || null;

    if (wizardSchema[type].types) {
      if (!objectType) {
        result.error = {
          type: "required",
          params: { type, property: "type" },
        };
        return result;
      }
    }

    for (let property of listProperties(type, { objectType })) {
      let value = object.get(property);

      result = this.validateValue(property, value, object, type, result);

      if (result.error) {
        break;
      }

      if (mapped(property, type)) {
        value = this.buildMappedJson(value);
      }

      if (value !== undefined && value !== null) {
        result[property] = value;
      }
    }

    if (!result.error) {
      for (let arrayObjectType of Object.keys(
        wizardSchema[type].objectArrays
      )) {
        let arraySchema = wizardSchema[type].objectArrays[arrayObjectType];
        let objectArray = object.get(arraySchema.property);

        if (arraySchema.required && !present(objectArray)) {
          result.error = {
            type: "required",
            params: { type, property: arraySchema.property },
          };
          break;
        }

        result[arraySchema.property] = [];

        for (let item of objectArray) {
          let itemProps = this.buildJson(item, arrayObjectType);

          if (itemProps.error) {
            result.error = itemProps.error;
            break;
          } else {
            result[arraySchema.property].push(itemProps);
          }
        }
      }
    }

    return result;
  },

  validateValue(property, value, object, type, result) {
    if (wizardSchema[type].required.indexOf(property) > -1 && !value) {
      result.error = {
        type: "required",
        params: { type, property },
      };
    }

    let dependent = wizardSchema[type].dependent[property];
    if (dependent && value && !object[dependent]) {
      result.error = {
        type: "dependent",
        params: { property, dependent },
      };
    }

    if (property === "api_body") {
      try {
        value = JSON.parse(value);
      } catch (e) {
        result.error = {
          type: "invalid",
          params: { type, property },
        };
      }
    }

    return result;
  },

  buildMappedJson(value) {
    if (typeof value === "string" || Number.isInteger(value)) {
      return value;
    }
    if (!value || !value.length) {
      return false;
    }

    let inputs = value;
    let result = [];

    inputs.forEach((inpt) => {
      let input = {
        type: inpt.type,
      };

      if (inpt.connector) {
        input.connector = inpt.connector;
      }

      if (present(inpt.output)) {
        input.output = inpt.output;
        input.output_type = snakeCase(inpt.output_type);
        input.output_connector = inpt.output_connector;
      }

      if (present(inpt.pairs)) {
        input.pairs = [];

        inpt.pairs.forEach((pr) => {
          if (present(pr.key) && present(pr.value)) {
            let pairParams = {
              index: pr.index,
              key: pr.key,
              key_type: snakeCase(pr.key_type),
              value: pr.value,
              value_type: snakeCase(pr.value_type),
              connector: pr.connector,
            };

            input.pairs.push(pairParams);
          }
        });
      }

      if (
        (input.type === "assignment" && present(input.output)) ||
        present(input.pairs)
      ) {
        result.push(input);
      }
    });

    if (!result.length) {
      result = false;
    }

    return result;
  },

  remove() {
    return ajax(`/admin/wizards/wizard/${this.id}`, {
      type: "DELETE",
    })
      .then(() => this.destroy())
      .catch(popupAjaxError);
  },
});

CustomWizardAdmin.reopenClass({
  all() {
    return ajax("/admin/wizards/wizard", {
      type: "GET",
    })
      .then((result) => {
        return result.wizard_list;
      })
      .catch(popupAjaxError);
  },

  submissions(wizardId, page = 0) {
    return ajax(`/admin/wizards/submissions/${wizardId}`, {
      type: "GET",
      data: {
        page,
      },
    }).catch(popupAjaxError);
  },

  create(wizardJson = {}) {
    const wizard = this._super.apply(this);
    wizard.setProperties(buildProperties(wizardJson));
    return wizard;
  },
});

export default CustomWizardAdmin;