const pg = require('pg');
const fs = require('fs');
const path = require('path');

const config = require('src/config/index.js');

// schema file name format ######_name.sql
const schemaDir = path.resolve(__dirname, '..', 'schemas');

const db = new pg.Client({
  host: config.database.host,
  port: config.database.port,
  user: config.database.user,
  password: config.database.password,
  database: config.database.dbname,
});

(async () => {
  await db.connect();

  await db.query(`select now();`);

  let version = -1;

  // check migrate record table exists
  const checkTable = await db.query(
    `
    select exists(
      select 1 
      from "information_schema"."tables"
      where
        "table_schema" = $1
        and "table_name" = $2
    ) as exists
  `,
    ['public', 'migrate_log']
  );

  if (checkTable.rowCount > 0 && checkTable.rows[0].exists === true) {
    // version table exists
    const maxVersion = await db.query(`select max("version")::integer as version from "public"."migrate_log"`);
    if (maxVersion.rowCount > 0 && maxVersion.rows[0] && maxVersion.rows[0].version !== null) version = maxVersion.rows[0].version; // eslint-disable-line
  } else {
    // create version table
    await db.query(`create table "public"."migrate_log" (
      "version" integer not null primary key,
      "created_time" timestamptz not null default now()
    );`);
  }

  console.info(`Database Now Version: ${version}`);

  // read all schema files
  const schemaList = await fs.promises.readdir(schemaDir);

  /**
   * @type {{[x: number]: boolean}}
   */
  const checkDuplicate = {};

  /**
   * @type {{version: number, filename: string}[]}
   */
  const versionList = schemaList
    .map(file => {
      const strs = file.split('_');
      const v = parseInt(strs[0], 10);
      if (isNaN(version)) throw new Error(`schema filename format error (######_name.sql)`); // eslint-disable-line

      if (v in checkDuplicate) throw new Error(`schema file version (${v}) is duplicate`);

      checkDuplicate[v] = true;

      return { version: v, filename: file };
    })
    .filter(t => t && t.version > version)
    .sort((a, b) => a.version - b.version);

  // 沒有需要更新的檔案
  if (versionList.length === 0) return;

  await db.query('begin');

  try {
    const vers = [];
    // write all schema file
    for (const it of versionList) {
      vers.push(`(${it.version})`);

      console.info(`Write Version: ${it.version}`);

      const fileContent = await fs.promises.readFile(path.resolve(schemaDir, it.filename), 'utf-8');

      await db.query(fileContent);
    }

    await db.query(`insert into "public"."migrate_log" ("version") values ${vers.join(',')}`);

    await db.query('commit');
  } catch (err) {
    await db.query('rollback');
    throw err;
  }
})()
  .then(() => {
    console.info('Database Migrate Finish');
  })
  .catch(err => {
    console.error('Database Migrate Failed, ', err);
    process.exit(1);
  })
  .finally(() => {
    db.end();
  });
