package LasTres::Schema::Result::Team;

use v5.36.0;

use strict;
use warnings;
use utf8;

use parent 'DBIx::Class::Core';

use LasTres::Location;
use JSON qw/to_json from_json/;

use Carp qw/cluck/;

use Moo;

__PACKAGE__->table('teams');

__PACKAGE__->add_columns(
    uuid => {
        data_type   => 'uuid',
        is_nullable => 0,
    },
    is_exploring => {
        data_type     => 'boolean',
        is_nullable   => 0,
        default_value => \'false',
    },
    action_frame => {
        data_type     => 'integer',
        is_nullable   => 0,
        default_value => \'0',
    },
    is_moving => {
        data_type     => 'boolean',
        is_nullable   => 0,
        default_value => \'false',
    },
    last_spawn => {
        data_type     => 'jsonb',
        is_nullable   => 0,
        default_value => \'\'null\'',
    },
    moving_to => {
        data_type     => 'jsonb',
        is_nullable   => 0,
        default_value => \'\'null\'',
    },
    leader => {
        data_type      => 'uuid',
        is_nullable    => 1,
        is_foreign_key => 1,
    },
    name => {
        data_type   => 'text',
        is_nullable => 0,
    },
    planet => {
        data_type   => 'text',
        is_nullable => 0,
        accessor    => '_planet',
    },
    super_area => {
        data_type   => 'text',
        is_nullable => 0,
        accessor    => '_super_area',
    },
    area => {
        data_type   => 'text',
        is_nullable => 0,
        accessor    => '_area',
    },
    location => {
        data_type   => 'text',
        is_nullable => 0,
        accessor    => '_location',
    },
    current_battle => {
        data_type   => 'uuid',
        is_nullable => 1,
    },
);

sub append_log_line ( $self, $line ) {
    for my $member ( $self->combat_members->@* ) {
        $member->append_log_line($line);
    }
}

sub is_defeated ($self) {
    $self = $self->get_from_storage;
    my @members       = $self->members;
    my @alive_members = grep { $_->health > 0 } @members;
    if ( !scalar @alive_members ) {
        return 1;
    }
    return 0;
}

sub combat_members_serializable ( $self, $pj = undef ) {
    my @team_members = $self->members;
    if ( defined $pj ) {
        @team_members = grep { $pj->uuid ne $_->uuid } @team_members;
        @team_members = ( $pj, @team_members );
    }
    my $team_pjs = [ map { $_->hash } (@team_members) ];
    return $team_pjs;
}

sub on_win_combat ($self) {
}

sub on_blackout ($self) {
    for my $pj ( $self->members ) {
        $pj->append_log_line(
            [
                {
                    text =>
'No queda nadie en el equipo que pueda luchar, volvéis al último punto de aparición.'
                }
            ]
        );
    }
    require LasTres::Redis;
    my $redis      = LasTres::Redis->new;
    my $last_spawn = $self->get_spawn;
    $last_spawn->place_team($self);
    $self->is_moving(0);
    $self->moving_to('null');
    for my $member ( $self->combat_members->@* ) {
        $member->health( $member->max_health );
        $member->mana( $member->max_mana );
        $member->update;
    }
    $self->update;
    for my $pj ( $self->members ) {
        $pj->update_team_sprites;
        $pj->update_location;
        $pj->update_actions;
    }
}

sub on_lose_combat ($self) {
    $self->on_blackout;
}

sub update ($self) {
    return $self->SUPER::update();
}

sub get_spawn ($self) {
    my $location;
    eval {
        $location =
          LasTres::Location::get( @{ from_json( $self->last_spawn ) } );
    };
    if ($@) {
        $location = $self->leader->race->spawn;
    }
    return $location;
}

sub start_random_combat ($self) {
    $self = $self->get_from_storage;
    my $location = $self->location;
    my $area     = $location->to_array->[2];
}

# May throw error, it is needed to handle.
sub location {
    my $self     = shift;
    my $location = shift;
    my $planet;
    my $super_area;
    my $area;
    if ( defined $location ) {
        $self->_location( $location->identifier );
        $area = $location->parent;
        $self->_area( $area->identifier );
        $super_area = $area->parent;
        $self->_super_area( $super_area->identifier );
        $planet = $super_area->parent;
        $self->_planet( $planet->identifier );
    }
    $location   = $self->_location;
    $area       = $self->_area;
    $super_area = $self->_super_area;
    $planet     = $self->_planet;
    $location =
      LasTres::Location::get( $planet, $super_area, $area, $location );
    return $location;
}

sub send_frame_to_members ($self) {
    require LasTres::Redis;
    my $redis = LasTres::Redis->new;
    $self = $self->get_from_storage;
    for my $pj ( $self->members ) {
        $redis->publish( $redis->pj_subscription($pj),
            to_json( { command => 'show-frame' } ) );
    }
}

sub combat_members ($self) {
    $self = $self->get_from_storage;
    my @members = $self->members;

    # Add friendly NPCs here when implemented.
    return [@members];
}

sub on_end_combat ($self) {
    require LasTres::Redis;
    my $redis = LasTres::Redis->new;
    for my $pj ( $self->members ) {
        $pj->update_team_sprites;
        $pj->update_location;
        $pj->update_actions;
    }
}

sub to_serializable ($self) {
    return {
        is_db => $JSON::true,
        uuid  => $self->uuid,
    };
}

sub from_serializable ( $class, $hash ) {
    require LasTres::Schema;
    my $schema    = LasTres::Schema->Schema;
    my $resultset = $schema->resultset('Team');
    if ( !$hash->{is_db} ) {
        die 'This is not a database Team.';
    }
    my @teams = $resultset->search( { uuid => $hash->{uuid} } );
    if ( !@teams ) {
        die 'This team does not exists.';
    }
    return $teams[0];
}

__PACKAGE__->set_primary_key('uuid');
__PACKAGE__->has_many( 'members', 'LasTres::Schema::Result::PJ', 'team' );
__PACKAGE__->belongs_to( 'leader', 'LasTres::Schema::Result::PJ' );

with 'LasTres::CombatCapableTeam';
1;
