_ = require 'lodash'
md5 = require 'md5'
{dirname, join, normalize} = require 'path'

States = {}

vision = angular.module 'vision'

Event = null
$(document).on 'click', (e) ->
  Event = e


vision.run ($rootScope, $mdDialog) ->

  $(document).on 'click', '.app-dialog-close', (e) -> $mdDialog.cancel()

  return


vision.factory '$vision', ($reactive, $state, $stateParams, $mdDialog, $rootScope) ->
  'ngInject'
  title: 'Vision'
  ready: no
  buttons: []
  states: {}
  attach: (module, scope, vm) ->

    currentState = $state.current.name
    @states[currentState] ?= {}

    vm ?= scope.vm
    $reactive(vm).attach(scope)
    vm._subscribe = vm.subscribe
    vm._call = vm.call

    vm.call = (file, name, args...) ->
      if file.indexOf('.') is 0
        name = "#{normalize(join(dirname(module.id),file))}--method--#{name}"
      else
        name = ".#{file}--method--#{name}"
      name = name.replace '.coffee--method', '--method'
      vm._call name, args...

    vm.subscribe = (file, name, args...) ->
      if file.indexOf('.') is 0
        name = "#{normalize(join(dirname(module.id),file))}--publish--#{name}"
      else
        name = ".#{file}--publish--#{name}"
      name = name.replace '.coffee--publish', '--publish'
      vm._subscribe name, args...

    __params = []

    vm._params = $stateParams

    vm.state =
      on: (param, cb) =>
        __params.push param
        @states[currentState][param] ?= []
        @states[currentState][param].push cb
        setTimeout (-> scope.$apply cb $stateParams), 300
      go: (param, value) =>
        params = $stateParams
        params[param] = value
        $state.go currentState, params, notify: no
        try
          cb params for cb in @states[currentState][param]
      dialog: (param, cb) =>
        vm.state.on param, _.debounce (params) ->
          # console.log params
          value = params[param]
          unless value
            do $mdDialog.cancel
          else
            config = cb params
            return null unless config
            if config.scope
              _scope = scope.$new yes
              _scope[key] = val for key, val of config.scope
            config.scope = _scope if _scope?
            if Event?
              # config.targetEvent = Event
              config.openFrom = Event.target
              config.closeTo = Event.target
              # console.log Event.target
            config.onRemoving ?= ->
              vm.state.go param, null
            $mdDialog.show config

      bind: (stateParam, ctrlValue, obj) =>
        if obj?
          _obj = {}; _obj[val] = key for key, val of obj
        scope.$watch "vm.#{ctrlValue}", (value) ->
          return null unless value?
          value = _obj[value] if obj?
          vm.state.go stateParam, value
        vm.state.on stateParam, (params) =>
          value = params[stateParam]
          value = obj[value] if obj?
          scope.vm[ctrlValue] = value


    # setTimeout =>
    #   array = []
    #   for param in __params
    #     for cb in @states[currentState][param]
    #       array.push
    #         param: $stateParams[param]
    #         cb: cb
    #   unless _.isEmpty array
    #     scope.$apply ->
    #       for one in array
    #         one.cb $stateParams
    # , 500
