#! /usr/bin/env node
import {resolve, dirname} from 'path';
import {readFileSync, writeFileSync} from 'fs';
import {createStore} from 'tinybase/store';
import {createTools} from 'tinybase/tools';
import {fileURLToPath} from 'url';

const UTF8 = 'utf8';

const isArray = (thing) => Array.isArray(thing);

const arrayForEach = (array, cb) => array.forEach(cb);
const arrayMap = (array, cb) => array.map(cb);

const object = Object;
const objEntries = object.entries;
const objNew = (entries = []) => object.fromEntries(entries);
const objToArray = (obj, cb) =>
  arrayMap(objEntries(obj), ([id, value]) => cb(value, id));
const objMap = (obj, cb) =>
  objNew(objToArray(obj, (value, id) => [id, cb(value, id)]));

const jsonParse = JSON.parse;

const FILE_ERROR = 'provide a valid schemaFile, storeName, and outputDir';
const log = (...lines) =>
  arrayForEach(lines, (line) =>
    process.stdout.write(`${line}
`),
  );
const err = (line) =>
  process.stderr.write(`ERROR: ${line}
`);
const getJson = (file) => jsonParse(readFileSync(file, UTF8));
const writeFile = (outputDir, fileName, content, label) => {
  const file = resolve(outputDir, fileName);
  log(label.padStart(23) + ': ' + file);
  writeFileSync(file, content, UTF8);
};
const getTools = (schemaFile) => {
  const schema = getJson(schemaFile);
  return createTools(
    createStore().setSchema(...(isArray(schema) ? schema : [schema])),
  );
};
const help = () => {
  log('', 'tinybase <command>', '', 'Usage:', '');
  objMap(commands, ([, args, help2], command) =>
    log(` tinybase ${command} ${args}`, ` - ${help2}`, ''),
  );
  log('See also http://tinybase.org/guides/developer-tools/command-line/', '');
};
const version = () =>
  log(
    getJson(resolve(dirname(fileURLToPath(import.meta.url)), '../package.json'))
      .version,
  );
const getStoreApi = async (schemaFile, storeName, outputDir) => {
  try {
    const [dTs, ts, uiReactDTs, uiReactTsx] =
      await getTools(schemaFile).getPrettyStoreApi(storeName);
    writeFile(outputDir, storeName + '.d.ts', dTs, 'Definition');
    writeFile(outputDir, storeName + '.ts', ts, 'Implementation');
    writeFile(
      outputDir,
      storeName + '-ui-react.d.ts',
      uiReactDTs,
      'UI React definition',
    );
    writeFile(
      outputDir,
      storeName + '-ui-react.tsx',
      uiReactTsx,
      'UI React implementation',
    );
  } catch {
    err(FILE_ERROR);
  }
};
const commands = {
  help: [help, '', 'print this message'],
  version: [version, '', 'get the current TinyBase version'],
  getStoreApi: [
    getStoreApi,
    '<schemaFile> <storeName> <outputDir>',
    'generate .d.ts, .ts, and .tsx API files from a schema file',
  ],
};
const main = () => {
  const [, , command, ...args] = process.argv;
  (commands[command]?.[0] ?? help)(...args);
};
main();
