package LasTres::Controller::Websocket::InputPacket::Init;

use v5.36.0;

use strict;
use warnings;

use feature 'signatures';

use Data::Dumper;

use Moo;

use JSON qw/to_json from_json/;

use LasTres::Flags;
use LasTres::DAO::PJs;

with 'LasTres::Controller::Websocket::InputPacket';

my $redis          = LasTres::Redis->new;
my $result_set_pjs = LasTres::DAO::PJs->ResultSet;

sub identifier {
    return 'init';
}

sub handle ( $self, $ws, $session, $data ) {
    if ( ref $data ne 'HASH' ) {
        return $ws->send( to_json( { error => "Data should be a hashref." } ) );
    }
    my $pj_uuid = $data->{pj_uuid};
    if ( !defined $pj_uuid ) {
        return $ws->send( to_json( { error => "No pj sent." } ) );
    }
    my @pjs = $result_set_pjs->search( { uuid => $pj_uuid } );
    if ( !scalar @pjs ) {
        return $ws->send( to_json( { error => 'This pj does not exists' } ) );
    }
    my $pj   = $pjs[0];
    my $user = $session->{user};
    if ( $pj->owner->uuid ne $user->uuid ) {
        return $ws->send(
            to_json( { error => 'You are not the owner of this pj.' } ) );
    }
    $session->{pj} = $pj;
    my $team     = $pj->team;
    my $location = $team->location;

    $pj->append_log_line(
        [
            {
                text       => 'Nueva conexion a este pj.',
                color      => 'red',
                background => 'black'
            },
        ]
    );

    if ( !$pj->get_flag( LasTres::Flags::INTRO_MESSAGE_SENT_FLAG() ) ) {
        $pj->set_flag(LasTres::Flags::INTRO_MESSAGE_SENT_FLAG);
        $pj->append_log_line(
            [
                { text => 'Bienvenido a ' },
                { text => 'LasTres', color => 'green' },
                { text => '. Esperamos que disfrutes del juego.' }
            ]
        );
        $pj->location->show_intro($pj);
        $pj->set_known_location( $pj->location );
    }

    my $info_packet_to_send =
      LasTres::Controller::Websocket::OutputPacket::Info->new(
        set_log => [ $pj->last_50_log ],
        $self->_location_data($pj),
        team_pjs    => $team->combat_members_serializable($pj),
        is_battling => defined $team->battle,
        $self->_enemy_team_pjs($session),
        clear => $JSON::true,
        $self->_available_actions($pj),
      );
    $info_packet_to_send->send($ws);
    my $redis = LasTres::Redis->new;
    $redis->subscribe(
        $redis->pj_subscription($pj),
        my $save = sub ( $message, $topic, $topics ) {
            return $self->_on_redis_event( $ws, $session, $message, $topic,
                $topics );
        }
    );
    $session->{redis} = $redis;
}

sub _enemy_team_pjs ( $self, $session ) {
    $session->{pj} = $session->{pj}->get_from_storage;
    my $pj         = $session->{pj};
    my $team       = $pj->team;
    my $enemy_team = $team->enemy_team;
    return (
          ( defined $enemy_team )
        ? ( enemy_team_pjs => $enemy_team->combat_members_serializable )
        : ()
    );
}

sub _location_data ( $self, $pj ) {
    my $connected_places = $self->_get_connected_places($pj);
    my $team             = $pj->team->get_from_storage;
    my $location         = $team->location;
    return (
        location_data => {
            current => $location->hash,
            (
                ( $team->is_moving )
                ? (
                    moving_to => LasTres::Location::get(
                        @{ from_json( $team->moving_to ) }
                    )->hash
                  )
                : ()
            ),
            connected_places => $connected_places,
        },
    );
}

sub _on_redis_event ( $self, $ws, $session, $message, $topic, $topics ) {
    my $data = from_json($message);
    $session->{pj} = $session->{pj}->get_from_storage;
    my $pj = $session->{pj};
    if ( $data->{command} eq 'append-log' ) {
        my $info_packet_to_send =
          LasTres::Controller::Websocket::OutputPacket::Info->new(
            append_log => $data->{log} );
        $info_packet_to_send->send($ws);
        return;
    }
    if ( $data->{command} eq 'update-location' ) {
        my $info_packet_to_send =
          LasTres::Controller::Websocket::OutputPacket::Info->new(
            $self->_location_data($pj) );

        $info_packet_to_send->send($ws);
        return;
    }
    if ( $data->{command} eq 'show-frame' ) {
        my $current_frame = $pj->team->action_frame;
        if ( $pj->team->is_moving ) {
            my $last_frame = $pj->team->location->parent->frames_to_move;
            LasTres::Controller::Websocket::OutputPacket::Info->new(
                remaining_frames => $last_frame - $current_frame )->send($ws);
        }
        return;
    }
    if ( $data->{command} eq 'update-team-sprites' ) {
        my $team = $pj->team;
        LasTres::Controller::Websocket::OutputPacket::Info->new(
            team_pjs    => $team->combat_members_serializable($pj),
            is_battling => defined $team->battle,
            $self->_enemy_team_pjs($session)
        )->send($ws);
    }
    if ( $data->{command} eq 'update-actions' ) {
        LasTres::Controller::Websocket::OutputPacket::Info->new(
            $self->_available_actions($pj) )->send($ws);
    }
}

sub _available_actions ($self, $pj) {
    return ( available_actions =>
          { map { $_->identifier => $_->hash($pj) } $pj->actions->@* }, );
}

sub _get_connected_places ( $self, $pj ) {
    my $team     = $pj->team;
    my $location = $team->location;

    my $connected_places = $location->get_available_locations_to_move_to($pj);
    @$connected_places = map { $_->hash } @$connected_places;
    return $connected_places;
}
1;
