module Brief class Server
    class Socket
      attr_reader :briefcases, :root, :websocket

      def initialize(options={})
        @root = Pathname(options.fetch(:root))
        @websocket = options.fetch(:websocket)
        @briefcases = {}.to_mash
        @briefcase_options = options.fetch(:briefcase_options, {})
        load_briefcases
        setup_interface
      end

      def process(message={})
        message.symbolize_keys!

        action      = message.fetch(:action)
        message_id  = message.fetch(:message_id)

        case

        when action == "brief:info"
          respond_to(message_id) do
            {
              environment: Brief.environment_info,
              root: root.to_s,
              briefcases: briefcases.keys
            }
          end

        when action == "run:command"
          command = message.fetch(:command, 'default')
          options = message.fetch(:options, {})
          briefcase = briefcases.fetch(message[:briefcase])

          respond_to(message_id) do
            briefcase.run_command(command, options)
          end
        when action == "list:briefcases"
          presenter = message.fetch(:presenter, 'default')
          options = message.fetch(:options, {})

          respond_to(message_id) do
            briefcases.values.map do |bc|
              bc.present(presenter, options)
            end
          end

        when action == "view:briefcase"
          presenter = message.fetch(:presenter, 'default')
          options = message.fetch(:options, {})
          briefcase = briefcases.fetch(message[:briefcase])

          respond_to(message_id) do
            briefcase.present(presenter.to_sym, options)
          end

        when action == "view:document"
          options = message.fetch(:options, {})
          path = message.fetch(:path)
          briefcase = briefcases.fetch(message[:briefcase])

          respond_to(message_id) do
            document = briefcase.document_at(path)
            document.to_model.as_json(options)
          end

        when action == "run:command"
          binding.pry
        when action == "query"
          params = message.fetch(:params, {})
          model_options = message.fetch(:model_options, {})
          briefcase = briefcases.fetch(message[:briefcase])

          respond_to(message_id) do
            briefcase.where(params).all.map do |model|
              model.as_json(model_options)
            end
          end

        else
          respond_to(message_id) do
            {error:"Invalid Action: #{ action }"}
          end
        end
      rescue
        nil
      end

      def respond_to(message_id, &block)
        body = block.call()

        payload = {
          action: "response",
          message_id: message_id,
          body: body
        }

        websocket.send(payload.to_json)
      end

      private

      def setup_interface
        socket = self

        websocket.onmessage do |raw|
          message = (JSON.parse(raw) rescue nil)

          puts "== Received Message: #{message}"
          socket.process(message)
        end
      end

      def briefcase_options
        (@briefcase_options || {})
      end

      def load_briefcases
        config_path = briefcase_options.fetch(:config_path, "brief.rb")

        root.children.select(&:directory?).each do |dir|
          if dir.join(config_path).exist?
            slug = dir.basename.to_s.parameterize
            @briefcases[slug] ||= Brief::Briefcase.new(briefcase_options.merge(root: dir))
          end
        end
      end

    end
  end
end