package App::Clifton::Tower::Jabber;

use aliased 'App::Clifton::UserConfigSet';
use aliased 'App::Clifton::ChainSetByJabberUser' => 'ChainSet';
use aliased 'Net::Async::XMPP::Client' => 'XMPP_Client';
use Log::Contextual qw(:log);
use Moo;

extends 'App::Clifton::Component';

has xmpp_client => (is => 'lazy');

sub xmpp_active { shift->xmpp_client->xmpp->is_loggedin }

has $_ => (is => 'ro', required => 1)
  for qw(bridge_name jabber_config irc_config);

has server => (is => 'ro', required => 1, weak_ref => 1);

has userconfig_set => (
  is => 'ro', # Moobug init_arg => undef,
  default => sub { UserConfigSet->new }
);

has chain_set => (
  is => 'ro', # Moobug init_arg => undef,
  default => sub { ChainSet->new }
);

sub _build_xmpp_client {
  my ($self) = @_;
  $self->_login_xmpp_client($self->_new_child(XMPP_Client, {
    on_message => $self->_replace_weakself('handle_message'),
  }));
}

sub _login_xmpp_client {
  my ($self, $xmpp) = @_;
  my $conf = $self->jabber_config;
  $xmpp->login(
    jid => $conf->user, host => $conf->server, password => $conf->pass,
  );
  $xmpp;
}

sub BUILD { $_[0]->xmpp_client }

sub handle_message {
  my ($self, $msg) = @_;

  my $me = $self->jabber_config->user;

  return log_debug {
    "Received message for ${\$msg->to} instead of $me - ignoring"
  } unless $msg->to eq $me;

  (my $from = $msg->from) =~ s/\/.*//;

  return log_debug {
    "Received message from me ($me) - ignoring"
  } if $from eq $me;

  return log_debug {
    "Received message from user ${from} not in my config"
  } unless my $user = $self->userconfig_set->get({ name => $from });

  if (my $chain = $self->chain_set->get({ jabber_user => $from })) {
    $chain->handle_xmpp_message($msg);
  } else {
    if ($msg->body =~ m{^\s*/start\s*$}) {
      $self->send_xmpp_message({
        to => $from, body => 'Connecting ...'
      });
      $self->start_chain_for($user)->on_finished(
        $self->_capture_weakself(sub {
          my ($self, $result) = @_;
          if ($result->{chain}) {
            $self->chain_set->add($result->{chain});
          }
          $self->send_xmpp_message({
            to => $from, body => 'Connection result: '.$result->{message}
          });
        })
      );
    } else {
      $self->send_xmpp_message({
        to => $from,
        body => 'Not currently connected - send /start to connect'
      });
    }
  }
}

sub send_xmpp_message {
  my ($self, $args) = @_;
  s/&/&amp;/g, s/"/&quot;/g, s/</&lt;/g, s/>/&gt;/g for $args->{body};
  $self->xmpp_client->compose(%$args)->send;
}

sub start_chain_for {
  my ($self, $user) = @_;
  $self->server->start_chain({
    jabber_tower => $self,
    jabber_user => $user->name,
    irc_tower => {
      server => $self->irc_config->server,
      irc_nick => $user->irc_nick
    },
    irc_channel => $self->irc_config->channel,
  });
}

1;

# and later

# package App::Clifton::Tower::IRC;

# has irc_client

# has irc_server_name

# has user_config

# has chain_set

# package App::Clifton::Chain

# 
