import {DriverManager, Connection, Statement, ResultSet, ColumnInfo} from "ndbc-connector";
import { MySQLDriver } from "..";
import { expect } from 'chai';

function getString(value:string, size:number, defaultValue:string = " ") {
  let str:string = "";
  let count:number = value === undefined || value == null ? 0 : value.length;
  for (let index = 0; index < size; index++) {
    if (index < count) {
      const element = value[index];
      str += element;
    } else {
      str += defaultValue;
    }
  }

  return str;
}

function printResult(result:ResultSet, size:number = 50):void {
  let columns:ColumnInfo[] = result.getMetadata();
  let count = columns.length;
  let columnLine = "";
  for (let i = 0; i < columns.length; i++) {
    const element = columns[i];
    columnLine += getString(element.getColumnName(), size) + "|";
  }

  console.log(columnLine);
  columnLine = "";
  for (let i = 0; i < columns.length; i++) {
    columnLine += getString("", size, "=") + "|";
  }

  console.log(columnLine);
  while(result.next()) {
    columnLine = "";
    for (let i = 0; i < columns.length; i++) {
      columnLine += getString(result.getValue(i), size) + "|";
    }
    console.log(columnLine);
  }
}

function initProperties(): Map<string, any> {
  let properties:Map<string, any> = new Map<string, any>();
  properties.set("host", "localhost");
  properties.set("database", "sakila");
  properties.set("user", "test");
  properties.set("password", "test");
  return properties;
}

beforeEach(function () {
  DriverManager.register("mysql", new MySQLDriver());
});

describe('init',  function () {
  it('Invalid Driver Name', async function () {
    try {
      let properties:Map<string, any> = new Map<string, any>();
      await DriverManager.connect("mysqla", properties).then<Connection, void>((value) => {
        expect(value).null;
        return value;
      });
    } catch (err) {
      expect(err).to.equal("The mysqla does not found.");
    }
  });

  it('Requirement Check', async function () {
    try {
      let properties:Map<string, any> = new Map<string, any>();
      await DriverManager.connect("mysql", properties).then<Connection, void>((value) => {
        expect(value).null;
        return value;
      });
    } catch (err) {
      expect(err.toString()).to.equal("Error: The user is required.");
    }
  });

  it('Simple Query', async function () {
    let connection:Connection | undefined;
    try {
      connection = await DriverManager.connect("mysql", initProperties());
      let statement:Statement = await connection.createStatement("SELECT * FROM actor");
      let resultSet:ResultSet = await statement.execute(new Map<string, object>());
      expect(resultSet.next()).true;
      expect(resultSet.getValue("actor_id")).to.equal(1);
      expect(resultSet.getValue("first_name")).to.equal('PENELOPE');
      expect(resultSet.getValue("last_name")).to.equal('GUINESS');
      expect(resultSet.getValue("last_update").getTime()).to.equal(new Date(2006, 1, 15, 4, 34, 33).getTime());
      let rowCount: number = 0;
      while(resultSet.next()) {
        rowCount ++;
      }

      expect(rowCount).greaterThan(100);
    } finally {
      if (connection !== undefined) {
        connection.close();
      }
    }
  });

  it('Meta Query', async function () {
    let connection:Connection | undefined;
    try {
      connection = await DriverManager.connect("mysql", initProperties());
      let statement:Statement = await connection.createStatement("SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA='sakila'");
      let resultSet:ResultSet = await statement.execute(new Map<string, object>());
      expect(resultSet.next()).true;
      expect(resultSet.getValue("TABLE_NAME")).to.equal('actor');
      let rowCount: number = 0;
      while(resultSet.next()) {
        rowCount ++;
      }
      expect(rowCount).greaterThan(10);
    } finally {
      if (connection !== undefined) {
        connection.close();
      }
    }
  });

  it('GetCatalogs', async function () {
    let connection:Connection | undefined;
    try {
      connection = await DriverManager.connect("mysql", initProperties());
      let resultSet:ResultSet = await connection.getMetadata().getCatalogs("");
      expect(resultSet.next()).false;
    } finally {
      if (connection !== undefined) {
        connection.close();
      }
    }
  });

  it('GetSchemas', async function () {
    let connection:Connection | undefined;
    try {
      connection = await DriverManager.connect("mysql", initProperties());
      let resultSet:ResultSet = await connection.getMetadata().getSchemas("", "sakila");
      expect(resultSet.next()).true;
      let rowCount: number = 0;
      while(resultSet.next()) {
        rowCount ++;
      }

      expect(rowCount).greaterThan(6);
    } finally {
      if (connection !== undefined) {
        connection.close();
      }
    }
  });

  it('GetTables', async function () {
    let connection:Connection | undefined;
    try {
      connection = await DriverManager.connect("mysql", initProperties());
      let resultSet:ResultSet = await connection.getMetadata().getTables("", "sakila", "", ["TABLE"]);
      expect(resultSet.next()).true;
      expect(resultSet.getValue("TABLE_NAME")).to.equal("actor");
      let rowCount: number = 0;
      while(resultSet.next()) {
        rowCount ++;
      }

      expect(rowCount).greaterThan(6);
    } finally {
      if (connection !== undefined) {
        connection.close();
      }
    }
  });

  it('GetColumns', async function () {
    let connection:Connection | undefined;
    try {
      connection = await DriverManager.connect("mysql", initProperties());
      let resultSet:ResultSet = await connection.getMetadata().getColumns("", "sakila", "actor");
      expect(resultSet.next()).true;
      expect(resultSet.getValue("TABLE_NAME")).to.equal("actor");
      expect(resultSet.getValue("COLUMN_NAME")).to.equal("actor_id");
      expect(resultSet.next()).true;
      expect(resultSet.getValue("COLUMN_NAME")).to.equal("first_name");
      expect(resultSet.next()).true;
      expect(resultSet.getValue("COLUMN_NAME")).to.equal("last_name");
      expect(resultSet.next()).true;
      expect(resultSet.getValue("COLUMN_NAME")).to.equal("last_update");
      expect(resultSet.next()).false;
    } finally {
      if (connection !== undefined) {
        connection.close();
      }
    }
  });
});