/**
 * * Copyright (c) 2016, Intel Corporation.
 *
 * This program is licensed under the terms and conditions of the
 * Apache License, version 2.0.  The full text of the Apache License is at
 * http://www.apache.org/licenses/LICENSE-2.0
 */

"use strict";

/**
 * This class will instantiate the ORM, load in the models, call the method
 * to create db connections, test the connection, then create the tables and
 * relationships if not present
 */
const fs = require('fs'),
  path = require('path'),
  Sequelize = require('sequelize'),
  config = require('config');

function init() {
  const db = {
    sequelize: new Sequelize(config.get("db.photos.host"), config.get("db.photos.options")),
    Sequelize: Sequelize
  };

  return db.sequelize.authenticate().then(function () {
    const Album = db.sequelize.define('album', {
      id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
      },
      path: Sequelize.STRING,
      name: Sequelize.STRING,
      parentId: {
        type: Sequelize.INTEGER,
        allowNull: true
      }
    }, {
      timestamps: false,
      classMethods: {
        associate: function() {
          Album.hasOne(Album, {as:'Album', foreignKey: 'parentId'});
        }
      }
    });

    const Photo = db.sequelize.define('photo', {
      id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
      },
      name: Sequelize.STRING,
      filename: Sequelize.STRING,
      added: Sequelize.DATE,
      modified: Sequelize.DATE,
      updated: Sequelize.DATE,
      scanned: Sequelize.DATE,
      taken: Sequelize.DATE,
      width: Sequelize.INTEGER,
      height: Sequelize.INTEGER,
      size: Sequelize.INTEGER,
      faces: {
        type: Sequelize.INTEGER,
        defaultValue: -1 /* not scanned */
      },
      duplicate: {
        type: Sequelize.BOOLEAN,
        defaultValue: 0
      },
      deleted: {
        type: Sequelize.BOOLEAN,
        defaultValue: 0
      },
      albumId: {
        type: Sequelize.INTEGER,
        allowNull: true,
        references: {
          model: Album,
          key: 'id',
        }
      }
    }, {
      timestamps: false
    });

    const Identity = db.sequelize.define('identity', {
      id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
      },
      lastName: Sequelize.STRING,
      firstName: Sequelize.STRING,
      middleName: Sequelize.STRING,
      name: {
        type: Sequelize.STRING,
        allowNull: false
      }
    }, {
      timestamps: false
    });

    const Face = db.sequelize.define('face', {
      id: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
      },
      photoId: {
        type: Sequelize.INTEGER,
        allowNull: false,
        references: {
          model: Photo,
          key: 'id',
        }
      },
      identityId: {
        type: Sequelize.INTEGER,
        allowNull: true,
        references: {
          model: Identity,
          key: 'id',
        }
      },
      identityDistance: { /* How far are markers from identity match? */
        type: Sequelize.DOUBLE,
        defaultValue: -1.0
      },
      faceConfidence: { /* How confident that this is a face? */
        type: Sequelize.DOUBLE,
        defaultValue: 0
      },
      lastComparedId: {
        type: Sequelize.INTEGER,
        allowNull: true,
      },
      top: Sequelize.FLOAT, /* 0..1 * photo.height */
      left: Sequelize.FLOAT, /* 0..1 * photo.width */
      bottom: Sequelize.FLOAT, /* 0..1 * photo.height */
      right: Sequelize.FLOAT, /* 0..1 * photo.width */
    }, {
      timestamps: false,
      classMethods: {
        associate: function() {
          Album.hasOne(Face, {as:'Face', foreignKey: 'lastComparedId'});
        }
      }
    });

    const FaceDistances = db.sequelize.define('facedistance', {
      face1Id: {
        type: Sequelize.INTEGER,
        allowNull: false,
        references: {
          model: Face,
          key: 'id',
        }
      },
      face2Id: {
        type: Sequelize.INTEGER,
        allowNull: false,
        references: {
          model: Face,
          key: 'id',
        }
      },
      distance: {
        type: Sequelize.DOUBLE,
        defaultValue: 1.0
      }
    }, {
      timestamps: false
    });

    const PhotoHash = db.sequelize.define('photohash', {
      hash: {
        type: Sequelize.STRING,
        primaryKey: true,
        unique: true
      },
      photoId: {
        type: Sequelize.INTEGER,
        allowNull: true,
        references: {
          model: Photo,
          key: 'id',
        }
      }
    }, {
      timestamps: false
    });

    return db.sequelize.sync({
      force: false
    }).then(function () {
      return db;
    });
  }).catch(function (error) {
    console.log("ERROR: Failed to authenticate with PHOTOS DB");
    console.log("ERROR: " + JSON.stringify(config.get("db"), null, 2));
    console.log(error);
    throw error;
  });
}

module.exports = init();
