#===============================================================================
# Huxley - Resource "remote" - Helper Functions
#===============================================================================
# Adding remote repositories onto a Huxley cluster requires some sophisticated
# configuration.  This file holds helper functions to stay organized.
{resolve, join} = require "path"
{async, project, shell, property, collect} = require "fairmont"
{force, where} = require "../helpers"
cluster = (require "../api-interface").cluster

# Check the API server to see if a specified cluster is online and ready.
is_ready = async (config, spec) ->
  # Build a data object to query the API's database for active clusters.
  return yield cluster.get
    cluster:
      name: spec.first
    huxley:
      url: config.huxley.url
      token: config.huxley.profile.token


module.exports =

  create:
    # Construct an object that will be passed to the Huxley API.
    build: (config, spec, cluster) ->
      {id, cluster} = cluster

      return {
        cluster:
          id: id
          name: spec.first
          address: "core@#{spec.first}.#{cluster.domain}"
        app:
          name: config.app_name
          domain: cluster.domain
        hook:
          address: "root@#{spec.first}.#{cluster.domain}:3000"
        huxley:
          url: config.huxley.url
          token: config.huxley.profile.token
      }

    # Check to see if this remote repository can be created.  Perhaps this should
    # be done with a 503 reply from the API if the cluster is not ready?
    check: async (config, spec) ->
      throw "Please provide a cluster name" unless spec.first

      response = yield is_ready(config, spec)
      if response.cluster.status != "online"
        throw "That cluster is not ready to accept a remote repository."

      # TODO: Check to see if there is an active "remote" on the cluster already.
      # Return data about the cluster
      return response

    # Complete additional setup, here and on the hook server.
    setup: async (options, config) ->
      # Add a "git remote" alias. The first command is allowed to fail.
      yield force shell, "git remote rm #{options.cluster.name}"
      yield shell "git remote add #{options.cluster.name} " +
        "ssh://#{options.hook.address}/root/repos/#{options.app.name}.git"

      # Transport files and directories listed in huxley.yaml to the hook server.
      {app, cluster} = options
      {files} = config
      if files && files != []
        # Tar every file and directory listed in "files" of huxley.yaml...
        tar = "tar -zcf - "
        tar += "#{file} " for file in files
        # ...and pipe the output to the hook server over SSH.
        yield shell tar + " | " +
          "ssh -A -o StrictHostKeyChecking=no " +
          "-o UserKnownHostsFile=/dev/null " +
          "-p 3000 root@#{cluster.name}.#{app.domain}  \"" +
          "cat > files/#{app.name}.tar.gz \""

        # Commit what we've just added to the "files" directory.
        yield shell "ssh -A -o StrictHostKeyChecking=no " +
          " -o UserKnownHostsFile=/dev/null " +
          "-p 3000 root@#{cluster.name}.#{app.domain} << EOF \n" +
          "cd files \n" +
          "git config --global user.email 'huxley@pandastrike.com' \n" +
          "git config --global user.name 'huxley-client' \n" +
          "git add -A \n" +
          "git commit -m 'Adding extra data from #{app.name}.' \n" +
          "EOF"

  delete:
    # Construct an object that will be passed to the Huxley API to used by its panda-hook library.
    build: (config, cluster) ->
      {cluster_id} = cluster

      return {
        cluster:
          id: cluster_id
        app:
          name: config.app_name
        huxley:
          url: config.huxley.url
          token: config.huxley.profile.token
      }


    # Check the application level config to make sure what the user's requesting can be done.
    check: async (config, spec) ->
      response = yield is_ready(config, spec)
      if response.cluster.status != "online"
        throw "The cluster is not ready.  Nothing to remove."

      # TODO: Check to see that there is a remote on the cluster in question.
      # if config.remotes?
      #   remotes = collect yield project "name", config.remotes
      #   unless spec.first in remotes
      #     throw "Error: The remote #{spec.first} is not registered with your account. Nothing to remove."
      # else
      #   throw "Error: The remote #{spec.first} is not registered with your account. Nothing to remove."

      return response



  passive:
    # For now, when Huxley adds "passive" repositories to the cluster, it doesn't get routed though
    # the API server.  For now, we just execute a series of shell commands.
    run: async (config, spec) ->
      response = yield is_ready(config, spec)
      unless response.cluster.status != "online"
        throw "The cluster is not ready to accept a remote repository."

      domain = response.cluster.domain

      # Shell to the specified cluster and create a bare repo.  Overwrite anything in our path.
      command =
        "ssh -A -o \"StrictHostKeyChecking no\"  -o \"UserKnownHostsFile=/dev/null\" " +
        "-p 3000 root@#{spec.first}.#{domain} << EOF\n" +
        "cd /root/passive \n " +
        "if [ -d #{config.repo_name}.git ]; then \n " +
        "  rm -rf #{config.repo_name}.git \n" +
        "fi \n " +
        "mkdir #{config.repo_name}.git \n " +
        "cd #{config.repo_name}.git \n " +
        "/usr/bin/git init --bare \n " +
        "EOF"

      yield shell command

      # Next, we will add this repository to the user's git remotes.  Allow "remote rm" to fail if neccessary, so do it separately.
      yield force shell, "git remote rm  #{spec.first}"
      yield shell "git remote add #{spec.first} ssh://root@#{spec.first}.#{domain}:3000/root/passive/#{config.repo_name}.git"

      # Because this does not cause a deployment, we can actually go ahead and push the
      # local repository to the passive remote. Initialize a git repo in the executable
      # path, commit everything, and push.
      command =
        "cd #{process.cwd()} &&" +
        "git init; " +
        "git add -A; "+
        "git commit -m 'Repo commited by Huxley to place on cluster.'; " +
        "git push #{config.repo_name} master"

      yield shell command
