const glob = require("glob");
const path = require("path");
const fs = require("fs-extra");
const axios = require('axios');
const conf=require(`${process.env.dirtown}/conf.json`)
const Checkjson = require(`./Checkjson.js`);

/* This manage Objects for indexing and check and act to CRUD
   objectpath/objects/schema/objectName.json
                     /objectNames/searchindes/objectName_valueofkey_uuildlist.json
                     /objectNames/uuid.json

*/
const Odmdb = {};
/*
Input: metaobject => data mapper of Key: Value

  objname + an object {} + action Checkjson => get a valid or not answer
  objname + an object {} + action search => apply matching algo to find probalistic object id
  objname + action index => update /searcindex of objects concern

*/
Odmdb.setObject=(schemaPath, objectPath, objectName, schema, lgjson, lg)=>{
  /** 
   * 
   * @schemapath {string} path to create or replace a schema ${schemaPath}/schema/
   * @objectPath {string} path where object are store 
   * @objectName {string} name of the object
   * @schema     {object} the json schema for this object
   * @lgjson     {object} the json file for a specific language
   * @lg         {string} the 2 letters language
   *
   * a shema   :
   *   schemaPath/schema/objectName.json
   *                    /lg/objectName_{lg}.json
   * an object :
   *   objectPath/objectName/idx/confjson ={"schema":"relativpathfile or http"}
   *                        /uniqueid.json defining schema
   *
  */
  if (!fs.existsSync(schemaPath)){
    return {status:404, ref:"Odmdb", info:"pathnamedoesnotexist", moreinfo:{fullpath:schemaPath}}
  }
  if (!fs.existsSync(objectPath)){
    return {status:404, ref:"Odmdb", info:"pathnamedoesnotexist",moreinfo:{fullpath:objectPath}}
  }
  // store schema file if not empty undefined or {}
  if (schema && !(Object.keys(schema).length === 0 && schema.constructor === Object)){
    fs.outputJSONSync(`${schemaPath}/schema/${objectName}.json`,schema, {spaces:2})
  }
  if (lgjson && lg && !(Object.keys(lgjson).length === 0 && lgjson.constructor === Object)){ 
    fs.outputJSONSync(`${schemaPath}/lg/${objectName}_${lg}.json`,lgjson, {spaces:2})
  }
  //create environnement object with the new schema config
  if (!fs.existsSync(`${objectPath}/${objectName}`)){
    fs.outputJsonSync(`${objectPath}/${objectName}/idx/confjson`,{schema:`${schemaPath}/schema/${objectName}.json`},{spaces:2})
  }
  return {status:200}
}

Odmdb.schema = (schemaPath, objectName, withschemacheck) => {
  // Return schema if exist and objectpath contain objectName { status:200;data:schema}
  if (!fs.existsSync(`${schemaPath}/${objectName}`))
    return {
      status: 404,
      info: "|odmdb|schemapathnamedoesnotexist",
      moreinfo: `${schemaPath}/${objectName}`,
    };
  if (!fs.existsSync(`${objectPath}/schema/${objectName}.json`)) {
    return {
      status: 404,
      info: `|odmdb|schemanotfound`,
      moreinfo: `file not found ${schemaPath}/schema/${objectName}.json`,
    };
  }
  const schema = fs.readJsonSync(`${schemaPath}/schema/${objectName}.json`);
  // check schema apx validity specificities primary unique ans searchindex
  if (withschemacheck) {
    if (!schema.apxprimarykey) {  
      // code 422: unprocessable Content
      return {
        status: 422,
        info: "|Odmdb|apxprimarykeynotfound",
        moreinfo: `${schemaPath}/schema/${objectName}.json`,
      };
    } else {
      if (
        !(
          schema.apxsearchindex[schema.apxprimarykey] &&
          schema.apxsearchindex[schema.apxprimarykey].list
        )
      ) {
        return {
          status: 422,
          info: "|Odmdb|apxprimaryketnotinsearchindexlist",
          moreinfo: `${schemaPath}/schema/${objectName}.json`,
        };
      }
      if (schema.apxuniquekey) {
        schema.apxuniquekey.forEach((k) => {
          if (
            !(
              schema.apxsearchindex[k] &&
              schema.apxsearchindex[k][schema.apxprimarykey]
            )
          ) {
            return {
              status: 422,
              info: "|Odmdb|apxuniquekeynotinsearchindex",
              moreinfo: `${schemaPath}/schema/${objectName}.json`,
            };
          }
        });
      }
    }
    const validschema = Checkjson.schema.validation(schema);
    if (validschema.status != 200) return validschema;
  }
  return {
    status: 200,
    data: schema,
  };
};

Odmdb.Checkjson = (objectPath, objectName, data, withschemacheck) => {
  /*
  @objectPath path to the folder that contain /objects/objectName/ /lg/objectName_{lg}.json /schema/objectName.json
  @objectName name of object
  @data data to check based on schema objectName definition
  
  @return status:200 Data is consistent with schema and primarykey does not exist
          status:201 Data is consistent with schema and primarykey does already exist
          status:other means unconsistent schema:
            404: schema does not exist
                 or unconsitent data and schema from Checkjson.js Checkjson.schema.data

  */
  const res = { status: 200 };
  //get schema link of object
    const schemaPath = fs.readJsonSync(`${objectPath}/${objectName}/idx/confjson`)['schema']
    if (schemaPath.substring(0,4)=="http"){
      // lance requete http pour recuperer le schema
    }else{
      schema=="!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
    }
  // check schema validity
  const schema = Odmdb.schema(objectPath, objectName, withschemacheck);
  if (schema.status != 200) return schema;
  console.log("SCHEMA for checking:");
  console.log(schema.data);
  console.log("DATA to check:");
  console.log(data);
  // withschemacheck at false, if check then it is done at Odmdb.schema
  const validate = Checkjson.schema.data(schema.data, data, false);
  if (validate.status != 200) {
    return validate;
  }
  if (
    schema.data.apxprimarykey &&
    data[k] &&
    fs.existsSync(`${objectPath}/${objectName}/${data[k]}.json}`)
  ) {
    res.status = 201; // means created => exist an object with this primary key
  }
  if (schema.data.apxuniquekey) {
    schema.data.apxuniquekey.forEach((k) => {
      if (
        data[k] &&
        fs.existsSync(
          `${objectPath}/${objectName}/searchindex/${objectName}_${k}_${schema.data.apxprimarykey}.json}`
        ) &&
        fs.readJsonSync(
          `${objectPath}/${objectName}/searchindex/${objectName}_${k}_${schema.data.apxprimarykey}.json}`
        )[k]
      ) {
        res.status = 201; // means created => exist as primary key
      }
    });
  }
  return res;
};
Odmdb.search = (objectPath, objectName, search) => {
  /*
  @search= {
    txt: string,
    algo: match | pattern | fuzzy
    fieldstring:[list of field],
    indexfilter:{index1:[val1,val2 | ] }
  }
  Return data:[uuids]

  example: search exact match hill in townId
   heavy search={txt:"hill",algo:"match",fieldstring:"toxnId"}
   light search={txt:"hill", algo:"match", indexfilter:{"key":"townId","value":[]}}
   light search={txt:"hill", algo:"match", indexfilter:{"key":"nationId","value":"ants"}}

   */
  const schema = Odmdb.schema(objectPath, objectName);
  if (schema.status != 200) return schema;
};
Odmdb.get = (objectPath, objectName, uuidprimarykeyList, fieldList) => {
  /*
  @uuidprimarykeyList list of uuid requested
  @fieldList key to return for each object
  Return objectName {status:200; data:{found:[{primarykey,field}],notfound:[uuid]}
  if all primarykey exist then data.notfound does not exist
  if all primarykey does not exist data.found does not exist
  */
  const res = { status: 200, data: {} };
  uuidprimarykeyList.forEach((id) => {
    if (fs.existsSync(`${objectPath}/${objectName}/${id}.json`)) {
      if (!res.data.found) res.data.found = [];
      const objectdata = fs.readJsonSync(
        `${objectPath}/${objectName}/${id}.json`
      );
      if (!fieldList) {
        res.data.found.push(objectdata);
      } else {
        const objinfo = {};
        fieldlList.forEach((k) => {
          if (objectdata[k]) objinfo[k] = objectdata[k];
        });
        res.data.found.push(objinfo);
      }
    } else {
      if (!res.data.notfound) res.data.notfound = [];
    }
  });
  return res;
};
Odmdb.create = (objectPath, objectName, data) => {
  /*
  Create an objects data into objectName 
  @objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json
  @objectName name of object
  @data data to check based on objectsMeta definition 
  */
};
Odmdb.update = (objectPath, objectName, data) => {
  /*
  Create an objects data into objectName 
  @objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json
  @objectName name of object
  @data data to check based on objectsMeta definition  
  */
};
Odmdb.delete = (objectPath, objectName, data) => {
  /*
  Create an objects data into objectName 
  @objectPath path to the folder that contain /objects/objectName/ /objectsInfo/objectName_lg.json /objectsMeta/objectName.json
  @objectName name of object
  @data data to check based on objectsMeta definition  
  */
};
/*console.log("test Odmdb");
console.log(
  Odmdb.check(
    "/media/phil/usbfarm/apxtrib/nationchains/socialworld/objects",
    "nations",
    { nationId: "123", status: "unchain" }
  )
);*/
module.exports = Odmdb;
