var lbry;

var command = '!tip';

module.exports={
  command: command,
  init: init,
  respond: respond
};

function init(rpcuser, rpcpassword) {
  if (lbry) {
    throw new Error('init was already called once');
  }

  var bitcoin = require('bitcoin');
  lbry = new bitcoin.Client({
    host: 'localhost',
    'port': 9245,
    'user': rpcuser,
    'pass': rpcpassword
  });
}

var globalSlackParams = {
  icon_emoji: ':rickshutup:'
};

function respond(bot, data) {
  var tipper = data.user,
      channel = data.channel,
      words = data.text.trim().split(' ').filter( function(n){return n !== "";} );

  if (words[0] !== command) {
    // if the received message isn't starting with the trigger -> ignore
    return;
  }

  if (!lbry) {
    bot.postMessage(channel, 'Failed to connect to lbrycrd', {icon_emoji: ':exclamation:'});
    return;
  }

  var subcommand = words.length >= 2 ? words[1] : 'help';

  var moveToBotSandbox = tipper != 'U0AFBMHCJ' && channel !== 'C1TEEBS2Z' && ['help', 'balance', 'deposit', 'withdraw'].indexOf(subcommand) != -1 && !channel.startsWith("D")
  if (moveToBotSandbox) {
    bot.postMessage(channel, 'Please use <#C1TEEBS2Z|bot-sandbox> to talk to bots.', globalSlackParams);
    return;
  }

  if (subcommand === 'help') {
    doHelp(bot, channel);
  }
  else if (subcommand === 'balance') {
    doBalance(bot, channel, tipper);
  }
  else if (subcommand === 'deposit') {
    doDeposit(bot, channel, tipper);
  }
  else if (subcommand === 'withdraw') {
    doWithdraw(bot, channel, tipper, words);
  }
  else {
    doTip(bot, channel, tipper, words);
  }
}



function doBalance(bot, channel, tipper) {
  lbry.getBalance(tipper, 1, function(err, balance) {
    if (err) {
      bot.postMessage(channel, '<@' + tipper + '>: Error getting balance', {icon_emoji: ':exclamation:'});
    }
    else {
      bot.postMessage(channel, '<@' + tipper + '>: You have *' + balance + '* LBC', globalSlackParams);
    }
  });
}


function doDeposit(bot, channel, tipper) {
  getAddress(tipper, function(err, address) {
    if (err) {
      bot.postMessage(channel, '<@' + tipper + '>: Error getting deposit address', {icon_emoji: ':exclamation:'});
    }
    else {
      bot.postMessage(channel, '<@' + tipper + '>: Your address is ' + address, globalSlackParams);
    }
  });
}


function doWithdraw(bot, channel, tipper, words) {
  if (words.length < 4) {
    doHelp(bot, channel);
    return;
  }

  var address = words[2],
      amount = getValidatedAmount(words[3]);

  if (amount === null) {
    bot.postMessage(channel, '<@' + tipper + '>: I dont know how to withdraw that many credits', globalSlackParams);
    return;
  }

  lbry.sendFrom(tipper, address, amount, function(err, txId) {
    if (err) {
      bot.postMessage(channel, err.message);
    }
    else {
      bot.postMessage(channel, '<@' + tipper + '>: You withdrew ' + amount + ' to ' + address + ' (' + txLink(txId) + ')', globalSlackParams);
    }
  });
}


function doTip(bot, channel, tipper, words) {
  if (words.length < 3) {
    doHelp(bot, channel);
    return;
  }

  var user = words[1],
      amount = getValidatedAmount(words[2]);

  if (amount === null) {
    bot.postMessage(channel, '<@' + tipper + '>: I dont know how to tip that many credits', globalSlackParams);
    return;
  }

  if (user.match(/^<@U[^>]+>$/)) {
    var id = user.substr(2,user.length-3);
    sendLbc(bot, channel, tipper, id, amount);
  }
  else {
    bot.getUser(user).then(function(data) {
      if (data.id) {
        sendLbc(bot, channel, tipper, data.id, amount);
      } else
      {
        bot.postMessage(channel, '<@' + tipper + '>: Sorry, I dont know that person', globalSlackParams);
      }
    })
  }
}


function doHelp(bot, channel) {
  var message =
    '`' + command + ' help`: this message\n' +
    '`' + command + ' balance`: get your balance\n' +
    '`' + command + ' deposit`: get address for deposits\n' +
    '`' + command + ' withdraw ADDRESS AMOUNT`: withdraw AMOUNT credits to ADDRESS\n' +
    '`' + command + ' USER AMOUNT`: send AMOUNT credits to USER\n';

    if (!channel.startsWith("D")) {
      message =
        '*USE <#C1TEEBS2Z|bot-sandbox> FOR EVERYTHING EXCEPT ACTUAL TIPPING*\n' +
        message +
        '\n' +
        '*Everyone will see what I say. Send me a Direct Message if you want to interact privately.*\n' +
        'If I\'m not responding in some channel, you can invite me by @mentioning me.\n';
    }

  bot.postMessage(channel, message, globalSlackParams);
}


function sendLbc(bot, channel, tipper, id, amount) {
  getAddress(id, function(err, address){
    if (err) {
      bot.postMessage(channel, err.message);
    }
    else {
      lbry.sendFrom(tipper, address, amount, 1, null, null, function(err, txId){
        if (err) {
          bot.postMessage(channel, err.message);
        }
        else {
          var message =
            'Wubba lubba dub dub! <@' + tipper + '> tipped <@' + id + '> ' + amount + ' LBC (' + txLink(txId) + '). ' +
            'DM me `!tip` for tipbot instructions.'
          bot.postMessage(channel, message, globalSlackParams);
        }
      });
    }
  });
};


function getAddress(userId, cb) {
  lbry.getAddressesByAccount(userId, function(err, addresses) {
    if (err) {
      cb(err);
    }
    else if(addresses.length > 0) {
      cb(null, addresses[0]);
    }
    else {
      lbry.getNewAddress(userId, function(err, address) {
        if (err) {
          cb(err);
        }
        else {
          cb(null, address);
        }
      });
    }
  });
}


function getValidatedAmount(amount) {
  amount = amount.trim();
  if (amount.toLowerCase().endsWith('lbc')) {
    amount = amount.substring(0, amount.length-3);
  }
  return amount.match(/^[0-9]+(\.[0-9]+)?$/) ? amount : null;
}


function txLink(txId) {
  return "<https://explorer.lbry.io/tx/" + txId + "|tx>";
}