<template>
  <div v-if="formState.ready">
    <gz-error :error-box-message="formState.errorBoxMessage"></gz-error>
    <div>
      <v-row>
        <v-col cols="12" sm="6" lg="4" xl="3">
          <v-select
            ref="ayaType"
            v-model="ayaType"
            :items="selectLists.importableAyaTypes"
            item-text="name"
            item-value="id"
            :label="$ay.t('AyaType')"
            data-cy="ayaType"
          ></v-select>
        </v-col>

        <v-col v-if="ayaType != 0" cols="12" sm="6" lg="4" xl="3">
          <v-checkbox
            v-model="doImport"
            :label="$ay.t('ImportNewRecords')"
          ></v-checkbox>
          <v-checkbox
            v-model="doUpdate"
            :label="$ay.t('UpdateExistingRecords')"
            color="warning"
          ></v-checkbox>
        </v-col>

        <v-col
          v-if="ayaType != 0 && (doImport || doUpdate)"
          cols="12"
          sm="6"
          lg="4"
          xl="3"
        >
          <v-file-input
            v-model="uploadFile"
            :label="$ay.t('FileToImport')"
            accept=".json, .csv, application/json, text/csv"
            prepend-icon="$ayiFileUpload"
            show-size
          ></v-file-input
          ><v-btn
            v-if="importable"
            :loading="uploading"
            color="primary"
            text
            @click="process"
            >{{ $ay.t("Import") }}</v-btn
          >
        </v-col>

        <v-col v-if="outputText != null" cols="12">
          <v-textarea
            v-model="outputText"
            full-width
            readonly
            auto-grow
            data-cy="outputText"
          ></v-textarea>
        </v-col>
      </v-row>
    </div>
  </div>
</template>
<script>
import Papa from "papaparse";
const FORM_KEY = "adm-import";
export default {
  data() {
    return {
      selectLists: {
        importableAyaTypes: []
      },
      uploadFile: [],
      ayaType: 0,
      doImport: false,
      doUpdate: false,
      outputText: null,
      rights: window.$gz.role.defaultRightsObject(),
      uploading: false,
      formState: {
        ready: false,
        dirty: false,
        valid: true,
        readOnly: false,
        loading: true,
        errorBoxMessage: null,
        appError: null,
        serverError: {}
      }
    };
  },
  computed: {
    importable() {
      return (
        (this.doImport || this.doUpdate) &&
        this.uploadFile &&
        this.uploadFile.name &&
        this.ayaType != 0
      );
    }
  },
  async created() {
    //NOTE:Global is what is checked for initialize to show this form and at server to allow import
    this.rights = window.$gz.role.getRights(window.$gz.type.Global);
    window.$gz.eventBus.$on("menu-click", clickHandler);
    await fetchTranslatedText(this);
    await populateSelectionLists(this);
    generateMenu(this);
    this.formState.ready = true;
  },
  beforeDestroy() {
    window.$gz.eventBus.$off("menu-click", clickHandler);
  },
  methods: {
    async process() {
      if (this.uploading) {
        return;
      }
      if (!this.uploadFile) {
        return;
      }
      this.uploading = true;
      this.outputText = null;
      try {
        let fileType = this.uploadFile.type.toLowerCase();
        if (!fileType.includes("csv") && !fileType.includes("json")) {
          throw new Error("Not supported file type, must be .csv or .json");
        }
        const isCSV = fileType.includes("csv");
        let dat = null;
        if (isCSV) {
          let res = await parseCSVFile(this.uploadFile);
          if (res.errors.length > 0) {
            this.outputText =
              "LT:CSV parsing errors:\n" + JSON.stringify(res.errors);
            throw new Error("LT:Errors in CSV file import can not proceed");
          }
          if (res.data) {
            dat = res.data;
          }
          //transform the input csv if it's not a direct match to json (part assembly etc)
          transform(dat, this.ayaType);
          //console.log("Done parseCSVFile");
        } else {
          dat = await parseJSONFile(this.uploadFile);
          //console.log("Done parse json");
        }

        // console.log(
        //   "The processed data before cleaning is ",
        //   JSON.stringify(dat)
        // );

        //strip out any unsupported fields before transmission
        cleanData(dat, this.ayaType);

        // console.log(
        //   "The processed data AFTER cleaning is ",
        //   JSON.stringify(dat)
        // );
        // eslint-disable-next-line no-debugger
        //debugger;

        //console.log("Flattened:", Flatten(dat));
        console.log(
          "if it was csv it should look like this:\n",
          Papa.unparse(dat)
        );

        //upload the data
         await this.upload(dat);
      } catch (error) {
        window.$gz.errorHandler.handleFormError(error);
      } finally {
        this.uploading = false;
      }
    },
    async upload(dat) {
      try {
        if (this.doUpdate == true) {
          let dialogResult = await window.$gz.dialog.confirmGeneric(
            "AdminImportUpdateWarning",
            "warning"
          );
          if (dialogResult == false) {
            return;
          }
        }

        const res = await window.$gz.api.post("import", {
          data: dat,
          atype: this.ayaType,
          doImport: this.doImport,
          doUpdate: this.doUpdate
        });
        if (res.error) {
          window.$gz.errorHandler.handleFormError(res.error);
        } else {
          //result is an array of strings
          let outText = "";
          res.data.forEach(function appendImportResultItem(value) {
            outText += value + "\n";
          });
          this.outputText = await window.$gz.translation.translateStringWithMultipleKeysAsync(
            outText
          );
        }
      } catch (error) {
        window.$gz.errorHandler.handleFormError(error);
      }
    },
    handleSelected() {}
  }
};

/////////////////////////////
//
//
function clickHandler(menuItem) {
  if (!menuItem) {
    return;
  }
  const m = window.$gz.menu.parseMenuItem(menuItem);
  if (m.owner == FORM_KEY && !m.disabled) {
    switch (m.key) {
      default:
        window.$gz.eventBus.$emit(
          "notify-warning",
          FORM_KEY + "::context click: [" + m.key + "]"
        );
    }
  }
}

//////////////////////
//
//
function generateMenu() {
  const menuOptions = {
    isMain: true,
    icon: "$ayiFileImport",
    title: "Import",
    helpUrl: "adm-import",
    menuItems: []
  };

  window.$gz.eventBus.$emit("menu-change", menuOptions);
}

//////////////////////////////////////////////////////////
//
// Ensures UI translated text is available
//
async function fetchTranslatedText() {
  await window.$gz.translation.cacheTranslations([
    "AyaType",
    "ImportNewRecords",
    "UpdateExistingRecords",
    "AdminImportUpdateWarning",
    "FileToImport"
  ]);
}

//////////////////////
//
//
async function populateSelectionLists(vm) {
  await window.$gz.enums.fetchEnumList("importable");
  vm.selectLists.importableAyaTypes = window.$gz.enums.getSelectionList(
    "importable"
  );
}

//////////////////////////////////////////////////////////
//
// Parse csv and return results as JSON, handle errors if any
//
async function parseCSVFile(file) {
  return new Promise(function(complete, error) {
    Papa.parse(file, {
      header: true,
      skipEmptyLines: true,
      dynamicTyping: true,
      worker: true,
      complete,
      error
    });
  });
}

//////////////////////////////////////////////////////////
//
// reformat JSON that was imported for types that need
// to be transformed (partassembly etc)
//
function transform(dat, atype) {
  switch (atype) {
    case window.$gz.type.PartAssembly:
      //json from csv needs reformatting
      dat.forEach(z => {
        var newItems = [];
        z.Items.split(",").forEach(x => {
          let o = x.split("|");
          newItems.push({
            PartNameViz: o[0],
            Quantity: Number.parseFloat(o[1])
          });
        });
        z.Items = newItems;
      });
      break;
    case window.$gz.type.TaskGroup:
      dat.forEach(z => {
        var newItems = [];
        z.Items.split(",").forEach((x, i) => {
          newItems.push({
            Sequence: i,
            Task: x
          });
        });
        z.Items = newItems;
      });
      break;
  }
  //console.log("transform after:", dat);
}

//////////////////////////////////////////////////////////
//
// Open local json file, read, parse and return results as JSON, handle errors if any
//
async function parseJSONFile(file) {
  return new Promise(function(complete) {
    const reader = new FileReader();
    reader.addEventListener(
      "load",
      () => {
        // this will then display a text file
        complete(JSON.parse(reader.result));
      },
      false
    );
    if (file) {
      reader.readAsText(file);
    }
  });
}

//////////////////////////////////////////////////////////
//
// remove unsupported props from data
//
function cleanData(dat, atype) {
  var allowedProps = [];
  //Note: convention here is any ID field that is linked object we want to support gets renamed here to replace *id with *viz if viz not already present
  //at back end it will attempt to match up but not create if not existing
  switch (atype) {
    case window.$gz.type.Customer:
      allowedProps.push(
        ...[
          "Name",
          "Active",
          "Notes",
          "Wiki",
          "Tags",
          "WebAddress",
          "AlertNotes",
          "BillHeadOffice",
          "HeadOfficeViz",
          "TechNotes",
          "AccountNumber",
          "ContractViz",
          "ContractExpires",
          "Phone1",
          "Phone2",
          "Phone3",
          "Phone4",
          "Phone5",
          "EmailAddress",
          "PostAddress",
          "PostCity",
          "PostRegion",
          "PostCountry",
          "PostCode",
          "Address",
          "City",
          "Region",
          "Country",
          "Latitude",
          "Longitude"
        ]
      );
      break;
    case window.$gz.type.HeadOffice:
      allowedProps.push(
        ...[
          "Name",
          "Active",
          "Notes",
          "Wiki",
          "Tags",
          "WebAddress",
          "TechNotes",
          "AccountNumber",
          "ContractViz",
          "ContractExpires",
          "Phone1",
          "Phone2",
          "Phone3",
          "Phone4",
          "Phone5",
          "EmailAddress",
          "PostAddress",
          "PostCity",
          "PostRegion",
          "PostCountry",
          "PostCode",
          "Address",
          "City",
          "Region",
          "Country",
          "Latitude",
          "Longitude"
        ]
      );
      break;
    case window.$gz.type.Part:
      allowedProps.push(
        ...[
          "Name",
          "Active",
          "Description",
          "Notes",
          "Wiki",
          "Tags",
          "ManufacturerViz",
          "ManufacturerNumber",
          "WholeSalerViz",
          "WholeSalerNumber",
          "AlternativeWholeSalerViz",
          "AlternativeWholeSalerNumber",
          "Cost",
          "Retail",
          "UnitOfMeasure",
          "UPC",
          "PartSerialsViz"
        ]
      );
      break;
    case window.$gz.type.PartAssembly:
      allowedProps.push(
        ...[
          "Name",
          "Active",
          "Notes",
          "Wiki",
          "Tags",
          "Items",
          "PartNameViz",
          "Quantity"
        ]
      );
      break;
    case window.$gz.type.PartWarehouse:
      allowedProps.push(...["Name", "Active", "Notes", "Wiki", "Tags"]);
      break;
    case window.$gz.type.Project:
      allowedProps.push(
        ...[
          "Name",
          "Active",
          "Notes",
          "Wiki",
          "Tags",
          "DateStarted",
          "DateCompleted",
          "ProjectOverseerViz",
          "AccountNumber"
        ]
      );
      break;
    case window.$gz.type.ServiceRate:
      allowedProps.push(
        ...[
          "Name",
          "Active",
          "Notes",
          "Wiki",
          "Tags",
          "AccountNumber",
          "Cost",
          "Charge",
          "Unit",
          "ContractOnly"
        ]
      );
      break;
    case window.$gz.type.TaskGroup:
      allowedProps.push(...["Name", "Active", "Notes", "Items"]);
      break;
    case window.$gz.type.TravelRate:
      allowedProps.push(
        ...[
          "Name",
          "Active",
          "Notes",
          "Wiki",
          "Tags",
          "AccountNumber",
          "Cost",
          "Charge",
          "Unit",
          "ContractOnly"
        ]
      );
      break;
  }

  //Strip out any records that have fields not on our allowed list
  dat.forEach(z => {
    for (const prop in z) {
      if (allowedProps.includes(prop) == false) {
        delete z[prop];
      } else {
        if (prop == "Tags") {
          //if it's coming from csv then Tags will be a string with comma separated items like this: blue,white,red
          //if it's json it will already be an array
          if (z.Tags && typeof z.Tags === "string") {
            z.Tags = z.Tags.split(",");
          }
        }
      }
    }
  });
}

/*  HOW TO GET PROPERTY NAMES EASILY 
Get the object from network traffic:
Assign it in code to a variable:
 var v = {
    Name: "XYZ Accounting",
    Active: true,
    Notes: "Ergonomic impactful info-mediaries",
    Wiki: null,
    CustomFields: null,
    Tags: ["black", "zone2", "zone3"],
    WebAddress: "https://example.biz",
    AlertNotes: null,
    BillHeadOffice: true,
    HeadOfficeId: 1,
    HeadOfficeViz: "XYZ Head Office",
    TechNotes: null,
    AccountNumber: "10402542",
    ContractId: null,
    ContractViz: null,
    ContractExpires: null,
    LastWorkOrderViz: 350,
    LastServiceDateViz: "2022-03-09T00:00:00Z",
    Phone1: "373-707-7322 x535",
    Phone2: "281.718.4551",
    Phone3: "1-452-791-5760 x84358",
    Phone4: null,
    Phone5: null,
    EmailAddress: "Annabel.Hahn64@example.org",
    PostAddress: null,
    PostCity: null,
    PostRegion: null,
    PostCountry: null,
    PostCode: null,
    Address: "9723 Tiara Summit",
    City: "Hansenside",
    Region: "Mississippi",
    Country: "Japan",
    Latitude: -7.7692,
    Longitude: 165.0654
  };
  In a javascript console use this Object.getOwnPropertyNames(<PASTE OBJECT HERE>); will output a nice array with field names
[
  "Name",
  "Active",
  "Notes",
  "Wiki",
  "CustomFields",
  "Tags",
  "WebAddress",
  "AlertNotes",
  "BillHeadOffice",
  "HeadOfficeId",
  "HeadOfficeViz",
  "TechNotes",
  "AccountNumber",
  "ContractId",
  "ContractViz",
  "ContractExpires",
  "LastWorkOrderViz",
  "LastServiceDateViz",
  "Phone1",
  "Phone2",
  "Phone3",
  "Phone4",
  "Phone5",
  "EmailAddress",
  "PostAddress",
  "PostCity",
  "PostRegion",
  "PostCountry",
  "PostCode",
  "Address",
  "City",
  "Region",
  "Country",
  "Latitude",
  "Longitude"
]




if it was csv it should look like this: 
Name,Active,Notes,Wiki,CustomFields,Tags,WebAddress,AlertNotes,BillHeadOffice,HeadOfficeViz,TechNotes,AccountNumber,ContractViz,ContractExpires,Phone1,Phone2,Phone3,Phone4,Phone5,EmailAddress,PostAddress,PostCity,PostRegion,PostCountry,PostCode,Address,City,Region,Country,Latitude,Longitude
"ACopyOf Altenwerth, Willms and Krajcik",true,Advanced web-enabled productivity,,,"black,white",https://example.info,,true,"Gerlach, Howe and Crist",,40810165,,,(868) 464-5253,1-788-655-8853 x08455,536.824.7646,,,Maximo_Ziemann10@example.net,00060 Davion Mission,East Kevonstad,Washington,Iraq,68361-2305,75163 Heller Plains,East Kevonstad,Washington,Iraq,33.3014,-157.7912
"ACopyOf Adams, Macejkovic and Stoltenberg",true,Multi-layered multi-tasking infrastructure,,,zone9,https://example.biz,,false,,,21491466,,,830-720-4993 x86044,1-306-960-6200 x0811,1-269-482-1221 x97391,,,Leanne99@example.com,4399 Hegmann Pass,South Velva,Georgia,Chile,44636-1335,6036 Reggie Pine,South Velva,Georgia,Chile,41.1883,-152.6866

*/
</script>
