const DateSystem = require('date-and-time')
const {DoCommand} = require('./db.js')
console.clear();

function tryParsInt(char) {
  try {
    return parseInt(char);
  } catch {
    return null;
  }
}

function CodeMeli(number) {
  if (number.length === 10) {
    let sum = 0;
    for (let i = 0; i < 9; i += 1) {
      const char = number.charAt(i);
      const num = tryParsInt(char);
      if (num == null) return false;
      sum += num * (10 - i);
    }
    const char = number.charAt(9);
    let left = sum % 11;
    if (left >= 2) left = 11 - left;
    const con = tryParsInt(char);
    if (con == null) return null;
    return left === con;
  }
  return false;
}

function GetBimeSherkat(bime, sherkatBime) {
  bime = tryParsInt(bime);
  const out = {bime: null, sherkat: null};
  if (bime === 1) out.bime = "آزاد";
  if (bime === 2) {
    sherkatBime = tryParsInt(sherkatBime);
    out.bime = "پایه(عمومی)";
    if (sherkatBime === 1) out.sherkat = "تامین اجتماعی";
    if (sherkatBime === 2) out.sherkat = "سلامت (خدمات درمان)";
    if (sherkatBime === 3) out.sherkat = "نیروهای مسلح";
  }
  
  if (bime === 3) {
    sherkatBime = tryParsInt(sherkatBime);
    out.bime = "پایه + تکمیلی";
    if (sherkatBime === 1) out.sherkat = "آتیه سازان";
    if (sherkatBime === 2) out.sherkat = "آسیا";
    if (sherkatBime === 3) out.sherkat = "البرز";
    if (sherkatBime === 4) out.sherkat = "ایران";
    if (sherkatBime === 5) out.sherkat = "دانا";
    if (sherkatBime === 6) out.sherkat = "دی";
    if (sherkatBime === 7) out.sherkat = "سینا";
    if (sherkatBime === 8) out.sherkat = "معلم";
    if (sherkatBime === 9) out.sherkat = "سایر";
  }
  
  if (bime === 4) {
    sherkatBime = tryParsInt(sherkatBime);
    out.bime = "ارگان";
    if (sherkatBime === 1) out.sherkat = "بانک ملی";
  }
  
  return out;
}

async function AddUserRecord(mobile, codeMeli, Bime, SherkatBime) {
  const now = new Date();
  const date = DateSystem.format(now, 'YYYY/MM/DD', true);
  const time = DateSystem.format(now, 'HH:mm:ss', true);
  const {bime, sherkat} = GetBimeSherkat(Bime, SherkatBime);
  const data = {
    date,
    time,
    reserveTime: null,
    reserveDate: null,
    mobile,
    codeMeli,
    bime,
    sherkat,
    IsReject: false,
    IsAccept: false, Sms: null,
  };
  const query = "Insert into Appointment SET ?";
  return await DoCommand(query, data);
}

class Query {
  constructor() {
    this.query = "";
  }
  
  Append(str) {
    this.query += str;
    return this;
  }
  
  NewLine(str) {
    this.query += "\n" + str;
    return this;
  }
  
  toString() {
    return this.query;
  }
}

class USSD {
  
  GetQuery(query) {
    let array = query.split(this.Splitter);
    array = array.filter(e => e.length > 0);
    array.splice(0, this.NumberPart);
    return array;
  }
  
  constructor(mainNumberPart = 1, splitter = '*') {
    this.Router = {};
    this.NumberPart = mainNumberPart;
    this.Splitter = splitter;
  }
  
  GetRoute(path) {
    path = path.toString();
    return this.Router[path] || {validate: null, response: null, name: null}
  }
  
  GetRouteByName(name, logs) {
    const ctx = this, keys = Object.keys(ctx.Router);
    for (let i = 0; i < keys.length; i += 1) {
      const row = ctx.Router[keys[i]]
      if (row.hasOwnProperty("name")) {
        if (row.name === name) return row.response(logs);
      }
    }
    return "";
  }
  
  GetRouteByDeep(deep, logs) {
    const ctx = this;
    return ctx.GetRoute.call(ctx, deep).response(logs);
  }
  
  AddRoute(path, route = {}) {
    path = path.toString();
    this.Router[path] = this.Router[path] || {};
    this.Router[path] = route;
  }
  
  async Executed(mobile, query, session_id, password) {
    const ctx = this, filterQuery = ctx.GetQuery.call(ctx, query);
    
    let deep = 0;
    const logs = {mobile, session_id};
    for (let i = 0; i < filterQuery.length; i += 1) {
      const value = filterQuery[i];
      const {validate, name} = ctx.GetRoute.call(ctx, deep);
      if (validate == null) return "[end]";
      try {
        if (validate(value, logs)) {
          logs[name] = value;
          deep += 1;
        }
      } catch {
        //ignored
      }
    }
    try {
      const {response} = ctx.GetRoute.call(ctx, deep);
      const end = response == null ? '[end]' : await response(logs);
      if (typeof end === 'string') return end;
      if (end.hasOwnProperty("route")) return await ctx.GetRouteByName.call(ctx, end.route, logs);
      if (end.hasOwnProperty("deep")) return await ctx.GetRouteByDeep.call(ctx, end.deep, logs);
    } catch {
      return '[end]';
    }
  }
}

const ussd = new USSD(2);
ussd.AddRoute(0, {
  name: "MainPage",
  validate: function (data, logs) {
    return CodeMeli(data);
  }, response: function (logs) {
    const query = new Query();
    query.Append("به سیستم نوبت دهی رادیولوژی نیکان خوش آمدید");
    query.NewLine("لطفا کد ملی بیمار را وارد کنید");
    return query.toString();
  }
});
ussd.AddRoute(1, {
  name: "Bime",
  validate: function (data, logs) {
    const bemeId = tryParsInt(data);
    return bemeId >= 1 && bemeId <= 3;
  }, response: function (logs) {
    const query = new Query();
    query.Append("نوع بیمه را انتخاب میکنید");
    query.NewLine("1)").Append("آزاد");
    query.NewLine("2)").Append("پایه(عمومی)");
    query.NewLine("3)").Append("پایه + تکمیلی");
    query.NewLine("4)").Append("ارگان");
    return query.toString();
  }
});


ussd.AddRoute(2, {
  name: "SherkatBime",
  validate: function (data, logs) {
    const bemeId = tryParsInt(logs.Bime);
    const sherkatBime = tryParsInt(data);
    
    if (bemeId != null && sherkatBime != null) {
      if (bemeId === 1) return true;
      if (bemeId === 2 && sherkatBime >= 1 && sherkatBime <= 3) return true;
      if (bemeId === 3 && sherkatBime >= 1 && sherkatBime <= 9) return true;
      if (bemeId === 4 && sherkatBime >= 1 && sherkatBime <= 1) return true;
    }
    
    return false;
  }, response: function (logs) {
    const bemeId = tryParsInt(logs.Bime)
    const query = new Query();
    if (bemeId === 1) {
      return {route: "Nobat"};
    }
    
    if (bemeId === 2) {
      query.Append("شرکت بیمه")
      query.NewLine("1)").Append("تامین اجتماعی");
      query.NewLine("2)").Append("سلامت (خدمات درمان)");
      query.NewLine("3)").Append("نیروهای مسلح");
    }
    
    if (bemeId === 3) {
      query.Append("شرکت بیمه")
      query.NewLine("1)").Append("آتیه سازان");
      query.NewLine("2)").Append("آسیا");
      query.NewLine("3)").Append("البرز");
      query.NewLine("4)").Append("ایران");
      query.NewLine("5)").Append("دانا");
      query.NewLine("6)").Append("دی");
      query.NewLine("7)").Append("سینا");
      query.NewLine("8)").Append("معلم");
      query.NewLine("9)").Append("سایر");
    }
    
    if (bemeId === 4) {
      query.Append("ارگان بیمه")
      query.NewLine("1)").Append("بانک ملی");
    }
    
    return query.toString();
  }
});
ussd.AddRoute(3, {
  name: "Nobat",
  validate: function (data, logs) {
    return true
  }, response: async function (logs) {
    const {mobile, MainPage, Bime} = logs;
    const {status, id} = await AddUserRecord(mobile, MainPage, Bime, Bime === '1' ? null : logs.SherkatBime);
    const query = new Query();
    if (status && id >= 0) query.Append("نتیجه درخواست شما از طریق پیامک ارسال میگردد");
    else query.Append("لطفا با مرکز تماس حاصل نمایید.");
    query.NewLine('[end]');
    return query.toString();
  }
});

// let query1 = "*500*5000005";
// query1 = "*500*5000005*0017904791";
// query1 = "*500*5000005*0017904791*123 123 123*123*3*123123*1";
// const result = ussd.Executed(mobile, query, session_id, password);
// console.log(result);
module.exports = {USSD: ussd};