import axios from "axios";

export const wotStoreModule = {
  namespaced: true,
  state: () => ({
    thingDescriptions: {},
    servient: null,
    helpers: null,
  }),
  mutations: {
    addThingDescription(state, { thingName, thingDescription }) {
      state.thingDescriptions[thingName] = thingDescription;
    },
    removeThingDescription(state, thingName) {
      delete state.thingDescriptions[thingName];
    },
    removeAllThingDescriptions(state) {
      state.thingDescriptions = {};
    },
  },
  actions: {
    async start() {
      // Set up thing client - not currently used.
    },
    async fetchThingDescription({ commit }, { uri, name = null }) {
      // Fetch the thing description from the given URI and consume it
      // NB this should only be called once, or we'll duplicate effort.
      // Deduplication should be done elsewhere.
      let response = await axios.get(uri);
      let td = response.data;
      let thing_name = name || uri.replace(/\/$/, "").split("/").pop();
      commit("addThingDescription", {
        thingName: thing_name,
        thingDescription: td,
      });
    },
    async fetchThingDescriptions({ commit }, uri) {
      // Fetch thing descriptions from the given URI
      let response = await axios.get(uri);
      if (response.status !== 200) throw "Could not retrieve thing descriptions";
      for (const k in response.data) {
        let thing_name = k.replace(/\/$/, "").replace(/^\//, "");
        commit("addThingDescription", {
          thingName: thing_name,
          thingDescription: response.data[k],
        });
      }
    },
  },
  getters: {
    thingDescriptions: (state) => {
      return state.thingDescriptions;
    },
    thingList: (state) => {
      return Object.keys(state.thingDescriptions);
    },
    thingDescription: (state) => (thingName) => {
      return state.thingDescriptions[thingName];
    },
    thingAvailable: (state) => (thingName) => {
      return thingName in state.thingDescriptions;
    },
    thingAffordanceAvailable: (state) => (thing, affordanceType, affordance) => {
      let td = state.thingDescriptions[thing];
      if (!td) {
        return false;
      }
      return affordance in td[affordanceType];
    },
    thingFormUrl:
      (state) =>
      (thing, affordanceType, affordance, op, allowUndefined = true) => {
        // Find the URL for a particular operation
        let td = state.thingDescriptions[thing];
        if (!td) {
          if (allowUndefined) return undefined;
          throw `Could not find form for ${affordanceType} ${thing}/${affordance} with op ${op}`;
        }
        let affordances = td[affordanceType];

        if (!affordances || !(affordance in affordances)) {
          if (allowUndefined) return undefined;
          throw `Could not find form for ${affordanceType} ${thing}/${affordance} with op ${op}`;
        }

        let href = findFormHref(affordances[affordance], op);
        if (href === undefined) {
          if (allowUndefined) return undefined;
          throw `Could not find form for ${affordanceType} ${thing}/${affordance} with op ${op}`;
        }
        // If we've found an href, prepend the `base` URL if appropriate
        if (href.startsWith("http")) return href;
        if ("base" in td) {
          let base = td.base;
          if (href.startsWith("/")) href = href.slice(1);
          if (!base.endsWith("/")) base += "/";
          return base + href;
        }
        return href;
      },
    thingPropertyUrl: (_state, getters) => (thing, property, op, allowUndefined) => {
      // Find the URL for a particular property
      return getters.thingFormUrl(thing, "properties", property, op, allowUndefined);
    },
    thingActionUrl: (_state, getters) => (thing, action, op, allowUndefined) => {
      // Find the URL for a particular action
      return getters.thingFormUrl(thing, "actions", action, op, allowUndefined);
    },
  },
};

export function findFormHref(affordance, op) {
  // Find the form in the affordance that matches the given operation type
  if (affordance === undefined) return undefined;
  let forms = affordance.forms;
  let matchingForm = forms.find((f) => f.op == op || f.op.includes(op));
  if (matchingForm === undefined) return undefined;
  return matchingForm.href;
}

export default wotStoreModule;
