lowdb = require 'lowdb'
fs = require 'fs'

class LowDBStore
  _optionDefaults:
    path: 'db.json'


  initialize: (@_contextName, [options]..., callback=->) ->
    @_defaults (options ?= {}), @_optionDefaults
    @_domainEventsCollectionName = "#{@_contextName}.DomainEvents"
    @_projectionCollectionName   = "#{@_contextName}.Projection"

    @db = lowdb
    @db.path = options.path
    if fs.existsSync options.path
      @db.load options.path

    callback null


  _defaults: (options, optionDefaults) ->
    allKeys = [].concat (Object.keys options), (Object.keys optionDefaults)
    for key in allKeys when !options[key] and optionDefaults[key]
      options[key] = optionDefaults[key]


  saveDomainEvent: (domainEvent, callback) ->
    callback null, @db(@_domainEventsCollectionName).insert(domainEvent).value()


  findAllDomainEvents: (callback) ->
    callback null, @db(@_domainEventsCollectionName).where().value()


  findDomainEventsByName: (names, callback) ->
    names = [names] if names not instanceof Array
    results = []
    for name in names
      results = [].concat @db(@_domainEventsCollectionName).where(name: name).value()
    callback null, results


  findDomainEventsByAggregateId: (aggregateIds, callback) ->
    aggregateIds = [aggregateIds] if aggregateIds not instanceof Array
    results = []
    for aggregateId in aggregateIds
      results = [].concat @db(@_domainEventsCollectionName).where(aggregate: id: aggregateId).value()
    callback null, results


  findDomainEventsByAggregateName: (aggregateNames, callback) ->
    aggregateNames = [aggregateNames] if aggregateNames not instanceof Array
    results = []
    for aggregateName in aggregateNames
      results = [].concat @db(@_domainEventsCollectionName).where(aggregate: name: aggregateName).value()
    callback null, results


  findDomainEventsByNameAndAggregateId: (names, aggregateIds, callback) ->
    names = [names] if names not instanceof Array
    aggregateIds = [aggregateIds] if aggregateIds not instanceof Array
    results = []
    for aggregateId in aggregateIds
      for name in names
        results = [].concat @db(@_domainEventsCollectionName).where(
          name: name
          aggregate: id: aggregateId
        ).value()
    callback null, results


  getProjectionStore: (projectionName, callback) ->
    callback null, @db "#{@_projectionCollectionName}.#{projectionName}"


  clearProjectionStore: (projectionName, callback) ->
    delete @db.db["#{@_projectionCollectionName}.#{projectionName}"]
    @db.save()
    callback()


module.exports = LowDBStore