<script>
import Swal from "sweetalert2";
import {authenticatedRequest, unauthenticatedRequest} from "@/components/session/authenticatedRequest.vue";

/**
 * The Global Objects object, which contains global functions for objects.
 */
export const ObjectsGlobal = {
  icons: {
    delete: 'fas fa-trash',
    info: 'fas fa-info',
    import: 'fas fa-file-import',
  },
  language: {
      title: (object) => {
        return `Opret ${object.meta.labels.single.toLowerCase()}`;
      },
      field: (object, column) => {
        return `Rediger ${object.columns[column].label.toLowerCase()}`;
      },
      collection: "Samling",
      split: "Opdel",
      save: "Gem",
      default: "Standard",
      required: "Påkrævet",
      no_applicable_booking_types: "Ingen gældende bookingtyper, prøv at vælge en anden afdeling.",
      optional: "Valgfri",
      rows: "Rækker",
      auto_start_on_lpr: "Auto-start ved LPR",
      close: "Luk",
      closed: "Lukket",
      related_service: "Relateret service",
      usage_log: "Brugslog",
      import_all: "Importer alle",
      note: "Note",
      import: "Importer",
      phone_country_code: "Landekode",
      succeeded: "Fuldførte",
      summary: "Oversigt",
      opening_hours: "Åbningstider",
      customers: "Kunder",
      selected: "Valgt",
      weekday: "Ugedag",
      opening_hour: "Åbningstid",
      closing_hour: "Lukketid",
      found: "Fundet",
      waiting: "Afventer",
      selected_multiple: "Valgte",
      queue: "Kø",
      in_progress: "behandles",
      failed: "Fejlede",
      barred: "Spærret",
      invalid: "Ugyldig",
      last_wash: "Sidste vask",
      have_not: "Har ikke",
      clear: "Ryd",
      have: "Har",
      hide: "Skjul",
      cancel: "Annuller",
      previous: "Tidligere",
      unselect: "Fravælg",
      select: "Vælg",
      month: "Måned",
      all: "Alle",
      copy: "Kopier",
      yes: "Ja",
      no: "Nej",
      email: "Email",
      subscriptions: "Abonnementer",
      invoice_already_created: "Faktura allerede oprettet",
      active: "Aktiv",
      inactive: "Inaktiv",
      password: "Adgangskode",
      customer: "Kunde",
      other_period: "Anden periode",
      phone_number: "Telefonnummer",
      no_data: "Ingen data",
      confirm_delete: "Ja, slet",
      confirm_delete_message: "Er du sikker på, at du vil slette dette objekt?",
      actions: "Handlinger",
      update: "Opdater",
      loading: "Indlæser",
      error: "Fejl",
      completed: "Fuldført",
      not_completed: "Ikke fuldført",
      nothing_to_do_all_set: "Sådan, der er ikke mere at gøre her!",
      mark_as_completed: "Marker som fuldført",
      delete: "Slet",
      submit: "Indsend",
      reset: "Nulstil",
      customer_name: 'Kundenavn',
      total: 'Total',
      status: 'Status',
      other: 'Andet',
      remove: 'Fjern',
      showing: 'Viser',
      add: 'Tilføj',
      reload: 'Genindlæs',
      time: {
        at_hour: 'Kl.',
        today: 'I dag',
        yesterday: 'I går',
        this_month: 'Denne måned',
        last_month: 'Sidste måned',
        this_year: 'I år',
        all: 'Altid',
        date: 'Dato',
      },
      error_messages: {
          not_array: 'Data er ikke en liste',
          not_object: 'Data er ikke et objekt',
          not_string: 'Data er ikke en tekststreng',
        },
      in: 'i',
      nothing_left_to_show: 'Der er ikke mere at vise',
      pending: 'Afventer',
      cancelled: 'Annulleret',
      show_content: 'Vis indhold',
      show: 'Vis',
      hide_content: 'Skjul indhold',
      quantity: 'Antal',
      manage: 'Administrer',
      customer_number: 'Kundenummer',
      payment: {
        method: 'Betalingsmetode',
        fixed_pricing: 'Fast pris',
        status: {
          pending: 'Afventer',
          succeeded: 'Fuldført',
          failed: 'Fejl',
          cancelled: 'Annulleret',
        },
        type: {
          card: 'Kort',
          bank_transfer: 'Bankoverførsel',
          cash: 'Kontant',
          other: 'Andet',
        },
        payment_recieved: 'Betaling modtaget',
        amount: 'Beløb',
        date: 'Dato',
        reference: 'Reference',
        transaction_id: 'Transaktions ID',
        payment_intent: 'Betalingsintention',
        receipt: 'Kvittering',
        receipt_url: 'Kvitterings URL',
        discount: 'Rabat',
      },
    invoice: 'Faktura',
  },
  requestOptions: {
    defaultOptions: {
      authenticated: true,
    },
    applyOptions: (optionsObject) => {
      return {
        ...ObjectsGlobal.requestOptions.defaultOptions,
        ...optionsObject
      };
    },
  },
  parse: {
    boolean: (value) => {
      return value === 'true';
    },
    number: (value) => {
      return parseInt(value);
    },
    string: (value) => {
      return value;
    },
  },
  set: {
    /**
     * Set a column in an object
     * @param {string} endpoint The endpoint of the object
     * @param {number} id The id of the object
     * @param {string} column The column to set
     * @param {string} value The value to set
     * @returns {Promise} The promise
     */
    column: async (endpoint, id, column, value) => {
      return authenticatedRequest(
        endpoint,
        "PUT",
        {
          id: id,
          [column]: value
        }
      );
    }
  },
  add: {
    /**
     * Add an object
     * @param {string} endpoint The endpoint of the object
     * @param {object} data The data (columns) of the object to add (e.g. [name = "Test", description = "Test"])
     * @param {object} optionsObject The options (e.g. {authenticated: false})
     * @returns {Promise} The promise
     */
    object: async (endpoint, data, optionsObject = {}) => {
      let options = ObjectsGlobal.requestOptions.applyOptions(optionsObject);
      if (options.authenticated) {
        return authenticatedRequest(
          endpoint,
          "POST",
          data
        );
      } else {
        return unauthenticatedRequest(
          endpoint,
          "POST",
          data
        );
      }
    }
  },
  delete: {
    /**
     * Delete an object
     * @param {string} endpoint The endpoint of the object
     * @param {number} id The id of the object
     * @returns {Promise} The promise
     */
    object: async (endpoint, id) => {
      return authenticatedRequest(
        `${endpoint}?id=${id}`,
        "DELETE"
      );
    }
  },
  get: {
    /**
     * Get an object
     * @param {string} endpoint The endpoint of the object
     * @param {number} id The id of the object
     * @param {object} optionsObject The options (e.g. {authenticated: false})
     * @returns {Promise} The promise
     */
    object: async (endpoint, id, optionsObject = {}) => {
      let options = ObjectsGlobal.requestOptions.applyOptions(optionsObject);
      if (options.authenticated) {
        return await authenticatedRequest(
          `${endpoint}?id=${id}`,
          "GET"
        ).then((response) => {
          return response.data.data;
        }).catch((error) => {
          console.error(error);
        });
      } else {
        return await unauthenticatedRequest(
          `${endpoint}?id=${id}`,
          "GET"
        ).then((response) => {
          return response.data.data;
        }).catch((error) => {
          console.error(error);
        });
      }
    },
    /**
     * Get all objects
     * @param {string} endpoint The endpoint of the object
     * @returns {Promise} The promise
     */
    objects: async (endpoint) => {
      return await authenticatedRequest(
        endpoint,
        "GET"
      ).then((response) => {
        return response.data.data;
      }).catch((error) => {
        console.error(error);
      });
    },
  },
  /**
   * Show the create object form
   * @param {object} object The object
   * @param {function} onAfterSubmit The function to call after the form is submitted
   * @param {object} lockedValues The locked values of the object (e.g. {department_id: 1})
   * @returns {Promise} The promise
   */
  showCreateObjectForm: async (object, onAfterSubmit = null, lockedValues = {}) => {
    let html = await ObjectsGlobal.generateCreateObjectForm(object.columns, lockedValues);
    return Swal.fire({
      title: ObjectsGlobal.language.title(object),
      html: html,
      showCancelButton: true,
      confirmButtonText: ObjectsGlobal.language.save,
      cancelButtonText: ObjectsGlobal.language.cancel,
      preConfirm: () => {
        // For each column in the object, get the value from the input field and add it to the object
        const argument_array = [];
        // Add the object add arguments in the same order as the add function
        for (const column in object.columns) {
          if (object.columns[column].creation.required) {
            try {
              if (document.getElementById(column).value === '') {
                throw new Error('Feltet ' + object.columns[column].label + ' er påkrævet.');
              }
            } catch (error) {
              Swal.showValidationMessage(
                  `${error}`
              );
              return false;
            }
            argument_array.push(document.getElementById(column).value);
          }
        }
        // Call the add function with the arguments
        object.add(...argument_array).then(() => {
          if (onAfterSubmit !== null) {
            onAfterSubmit();
          }
        });
      }
    });
  },
  generateCreateObjectForm: async (columns, lockedValues) => {
    let html = '';
    // Check if the column is a locked value
    function isLockedValue(column) {
      return lockedValues[column] !== undefined;
    }
    // If it is a locked value, set the value to the locked value
    function getLockedValue(column, defaultValue = '') {
      return lockedValues[column] !== undefined ? lockedValues[column] : '';
    }
    // Add the form fields
    for (const column in columns) {
      if (columns[column].creation.required) {
        switch (columns[column].type) {
          case 'string':
            html += `<div class="field">
              <label class="label has-text-black">${columns[column].label}</label>
              <div class="control">
                <input class="input has-background-light has-text-black" type="text" id="${column}">
              </div>
            </div>`;
            break;
          case 'number':
            html += `<div class="field" style="display: ${isLockedValue(column) ? 'none' : 'block'}">
              <label class="label has-text-black">${columns[column].label}</label>
              <div class="control">
                <input class="input has-background-light has-text-black" type="number" id="${column}" value="${getLockedValue(column)}" ${isLockedValue(column) ? 'disabled' : ''}>
              </div>
            </div>`;
            break;
          case 'boolean':
            html += `<div class="field">
              <label class="label has-text-black">${columns[column].label}</label>
              <div class="control">
              <!-- Select -->
              <div class="select is-fullwidth">
                <select id="${column}" class="has-background-light has-text-black">
                  <option value="true">Ja</option>
                  <option value="false">Nej</option>
                </select>
              </div>
            </div>`;
            break;
          case 'datetime':
            html += `<div class="field">
              <label class="label has-text-black">${columns[column].label}</label>
              <div class="control">
                <input class="input has-background-light has-text-black" type="datetime-local" id="${column}">
              </div>
            </div>`;
            break;
          case 'select':
            //var isLocked = lockedValues[column] !== undefined;
            html += `<div class="field">
                <label class="label has-text-black">${columns[column].label}</label>
                <div class="control">
                <!-- Select -->
                <div class="select is-fullwidth">
                  <select id="${column}" class="has-background-light has-text-black" ${isLockedValue(column) ? 'disabled' : ''} >`;
            // Check if the columns options are a function, if so, call it (and wait for it to finish). Otherwise, make the array awaitable
            var awaitOptions = columns[column].options;
            if (typeof columns[column].options === 'function') {
              awaitOptions = columns[column].options();
            } else {
              awaitOptions = new Promise((resolve) => {
                resolve(columns[column].options);
              });
            }
            // Wait for the options to be ready
              await awaitOptions.then((response) => {
              // How long are the list of options
              for (let i = 0; i < response.length; i++) {
                var tmp = response[i];
                // Check if the column exists in the locked values
                //var lockedValue = lockedValues[column] === tmp.id ? 'selected' : '';
                //html += `<option value="${tmp.id}" ${lockedValue}>`;
                html += `<option value="${tmp.id}" ${getLockedValue(column) === tmp.id ? 'selected' : ''}>`;
                html += `${tmp.name}`;
                html += `</option>`;
              }
            });
            html += `</select>
                </div>
              </div>`;
            break;
        }
      }
    }
    // Return the form
    return html;
  },
  async generateEditObjectFieldForm(object, column, value) {
    let html = '';
    function ifNullDefault(value, defaultValue) {
      return value === null ? defaultValue : value;
    }
    switch (object.columns[column].type) {
      case 'string':
        html += `<div class="field">
          <label class="label has-text-black">${object.columns[column].label}</label>
          <div class="control">
            <input class="input has-background-light has-text-black" type="text" id="${column}" value="${ifNullDefault(value, '')}">
          </div>
        </div>`;
        break;
      case 'number':
        html += `<div class="field">
          <label class="label has-text-black">${object.columns[column].label}</label>
          <div class="control">
            <input class="input has-background-light has-text-black" type="number" id="${column}" value="${value}">
          </div>
        </div>`;
        break;
      case 'boolean':
        html += `<div class="field">
          <label class="label has-text-black">${object.columns[column].label}</label>
          <div class="control">
          <!-- Select -->
          <div class="select is-fullwidth">
            <select id="${column}" class="has-background-light has-text-black">
              <option value="true" ${value === true ? 'selected' : ''}>${ObjectsGlobal.language.yes}</option>
              <option value="false" ${value === false ? 'selected' : ''}>${ObjectsGlobal.language.no}</option>
            </select>
          </div>
        </div>`;
        break;
      case 'select':
        html += `<div class="field">
            <label class="label has-text-black">${object.columns[column].label}</label>
            <div class="control">
            <!-- Select -->
            <div class="select is-fullwidth">
              <select id="${column}" class="has-background-light has-text-black">`;
        await object.columns[column].options().then((response) => {
          console.log(response);
          // How long are the list of options
          for (let i = 0; i < response.length; i++) {
            var tmp = response[i];
            console.log(tmp);
            html += `<option value="${tmp.id}">${tmp.name}</option>`;
          }
        });
        html += `</select>
            </div>
          </div>`;
        break;
    }
    return html;
  },
  showEditObjectFieldForm: async (object, id, column, value, onAfterSubmit = null) => {
    let html = await ObjectsGlobal.generateEditObjectFieldForm(object, column, value);
    return Swal.fire({
      title: ObjectsGlobal.language.field(object, column),
      html: html,
      showCancelButton: true,
      confirmButtonText: ObjectsGlobal.language.save,
      cancelButtonText: ObjectsGlobal.language.cancel,
      preConfirm: () => {
        try {
          // Call the set function with the arguments
          object.set[column](id, document.getElementById(column).value).then(() => {
            if (onAfterSubmit !== null) {
              onAfterSubmit();
            }
          });
        } catch (error) {
          console.error('Unable to edit object field', error);
          // Show an error message
          Swal.showValidationMessage(
              `Fejl: ${error}`
          );
        }
      }
    });
  },
  showObjects: async (object, displayColumns = null, filters = {}, displayActions = false) => {
    let html = '';
    // Get the objects
    await object.get.all().then((objects) => {
      // Filter the objects
      if (Object.keys(filters).length > 0) {
        objects = objects.filter((object) => {
          for (const filter in filters) {
            if (object[filter] !== filters[filter]) {
              return false;
            }
          }
          return true;
        });
      }
      // Add the table
      html += `<table class="table is-fullwidth has-text-left has-background-light">
        <thead>
        <tr>`;
      // Add the table headers
      if (displayColumns === null) {
        for (const column in object.columns) {
          html += `<th class="has-text-black">${object.columns[column].label}</th>`;
        }
      } else {
        for (const column in displayColumns) {
          html += `<th class="has-text-black">${object.columns[column].label}</th>`;
        }
      }
      if (displayActions) {
        html += `<th  class="has-text-black">Handlinger</th>`;
      }
      html += `
        </tr>
        </thead>
        <tbody>`;
      // Add the table rows
      for (let i = 0; i < objects.length; i++) {
        html += `<tr>`;
        // Add the table columns
        if (displayColumns === null) {
          for (const column in object.columns) {
            html += `<td class="has-text-black">${objects[i][column]}</td>`;
          }
        } else {
          for (const column in displayColumns) {
            html += `<td class="has-text-black">${objects[i][column]}</td>`;
          }
        }
        // Add the actions column
        if (displayActions) {
          html += `<td>
          <button class="button is-small is-info" @click="showEditObjectFieldForm(${objects[i].id}, 'name', '${objects[i].name}')">Rediger</button>
          <button class="button is-small is-danger" @click="deleteObject(${objects[i].id})">Slet</button>
        </td>`;
          html += `</tr>`;
        }
      }
      // If the list is empty
      if (objects.length === 0) {
        html += `<tr>
          <td colspan="${Object.keys(object.columns).length + 1}">${ObjectsGlobal.language.no_data}</td>
        </tr>`;
      }
      html += `</tbody>
      </table>`;
    });
    return Swal.fire({
      title: object.meta.title,
      html: html,
      showCancelButton: !displayActions,
      showConfirmButton: displayActions,
      confirmButtonText: ObjectsGlobal.language.save,
      cancelButtonText: ObjectsGlobal.language.cancel,
    });
  },
  showDeleteObjectForm: async (object, id, onAfterSubmit = null) => {
    return Swal.fire({
      title: `Fjern ${object.meta.labels.single}?`,
      text: ObjectsGlobal.language.confirm_delete_message,
      showCancelButton: true,
      showConfirmButton: true,
      confirmButtonText: ObjectsGlobal.language.confirm_delete,
      cancelButtonText: ObjectsGlobal.language.cancel,
      showLoaderOnConfirm: true,
      preConfirm: () => {
        object.delete(id).then(() => {
          if (onAfterSubmit !== null) {
            onAfterSubmit();
          }
        });
      }
    });
  }
};
</script>