package LasTres::CombatCapableEntity;

use v5.36.0;

use strict;
use warnings;
use utf8;

use feature 'signatures';

use Moo::Role;
use JSON qw/to_json from_json/;

requires(
    'uuid',          'race_string',   'nick',           'born_stats',
    'health',        'mana',          'training_stats', 'experience',
    'combat_action', 'combat_target', 'team',
    'gain_experience', 'update_team_sprites', 'get_from_storage',
);

sub append_log_line {
}

sub race ($self) {
    my $hash;
    $hash = LasTres::Races->new->hash;
    if ( $self->isa('LasTres::Schema::Result::PJ') ) {
        $hash = LasTres::Races->new->hash_playable;
    }
    my $race = $hash->{ $self->race_string };
    if ( !defined $race ) {
        die "Not valid race for entity " . $self->uuid;
    }
    return $race;
}

## OVERRIDE (Call super)
sub update($self) {
    $self = $self->get_from_storage;
    if ( $self->health < 1 ) {
        $self->on_faint;
    }
}

sub attack ( $self, $enemy_entity ) {
    my $defense = $enemy_entity->resistance;
    my $attack  = $self->strength;
    my $level   = $self->level;

    # This should change with the different attacks.
    my $power  = 20;
    my $damage = int(
        ( ( ( 2 * $level ) / 5 + 2 ) * $power * $attack / $defense ) / 50 + 2 );
    my $final_health = $enemy_entity->health - $damage;
    if ( $final_health < 0 ) {
        $final_health = 0;
    }
    $enemy_entity->health($final_health);
    my $team1 = $self->team;
    my $team2 = $enemy_entity->team;
    require LasTres::Redis;
    my $redis = LasTres::Redis->new;
    for my $team ( $team1, $team2 ) {
        next if !$team->isa('LasTres::Schema::Result::Team');
        for my $pj ( $team->members ) {
            $redis->publish( $redis->pj_subscription($pj),
                to_json( { command => 'update-team-sprites' } ) );
        }
    }
    for my $member ( $team1->combat_members->@* ) {
        $member->append_log_line(
            [
                { color => 'green', text => "@{[$self->nick]}" },
                {
                    text => ' atacó a '
                },
                { color => 'red', text => "@{[$enemy_entity->nick]}" },
                {
                    text => ". Le causó $damage puntos de daño, ",
                },
                {
                    text =>
"vida restante @{[$enemy_entity->health]}/@{[$enemy_entity->max_health]}."
                }
            ]
        );
    }
    for my $member ( $team2->combat_members->@* ) {
        $member->append_log_line(
            [
                { color => 'red', text => "@{[$self->nick]}" },
                {
                    text => ' atacó a '
                },
                { color => 'green', text => "@{[$enemy_entity->nick]}" },
                {
                    text => ". Le causó $damage puntos de daño, ",
                },
                {
                    text =>
"vida restante @{[$enemy_entity->health]}/@{[$enemy_entity->max_health]}."
                }
            ]
        );
    }
    $enemy_entity->update;
}

sub on_faint($self) {
    my $team2 = $self->team;
    for my $member ( $team2->combat_members->@* ) {
        $member->append_log_line(
                [
                { color => 'green', text => "@{[$self->nick]}" },
                { text  => " se ha debilitado." },
            ]
        );
    }
    my $battle = $team2->battle;
    if (!defined $battle) {
        return;
    }
    my $team1 = $battle->get_enemy_team($team2);
    for my $member ( $team1->combat_members->@* ) {
        $member->append_log_line(
                [
                { color => 'red', text => "@{[$self->nick]}" },
                { text  => " se ha debilitado." },
            ]
        );
        $member->gain_experience((($self->race->experience_drop_base * $self->level)/7));
    }

}

sub level ($self) {

    # Floating point trick, works in level 100,
    # for upper levels maybe it may need adjusting.
    return int( $self->experience**( 1 / 3 ) + 0.0000000000001 );
}

sub max_health ($self) {
    my $races            = LasTres::Races->new;
    my $race             = $self->race;
    my $health_base_race = $race->base_stats->health;
    my $health_born      = $self->born_stats->health;
    my $health_training  = $self->training_stats->health;
    my $health_mix =
      2 * $health_base_race + $health_born + ( $health_training / 4 );
    my $health_scaled = ( ( $health_mix * $self->level ) / 100 );
    return int( $health_scaled + $self->level + 10 );
}

sub strength ($self) {
    my $races              = LasTres::Races->new;
    my $race               = $self->race;
    my $strength_base_race = $race->base_stats->strength;
    my $strength_born      = $self->born_stats->strength;
    my $strength_training  = $self->training_stats->strength;
    my $strength_mix =
      2 * $strength_base_race + $strength_born + ( $strength_training / 4 );
    my $strength_scaled = ( ( $strength_mix * $self->level ) / 100 );
    return int( ( $strength_scaled + 5 ) * 1.1 );
}

sub speed ($self) {
    my $races           = LasTres::Races->new;
    my $race            = $self->race;
    my $speed_base_race = $race->base_stats->speed;
    my $speed_born      = $self->born_stats->speed;
    my $speed_training  = $self->training_stats->speed;
    my $speed_mix =
      2 * $speed_base_race + $speed_born + ( $speed_training / 4 );
    my $speed_scaled = ( ( $speed_mix * $self->level ) / 100 );
    return int( ( $speed_scaled + 5 ) * 1.1 );
}

sub intelligence ($self) {
    my $races                  = LasTres::Races->new;
    my $race                   = $self->race;
    my $intelligence_base_race = $race->base_stats->intelligence;
    my $intelligence_born      = $self->born_stats->intelligence;
    my $intelligence_training  = $self->training_stats->intelligence;
    my $intelligence_mix =
      2 * $intelligence_base_race +
      $intelligence_born +
      ( $intelligence_training / 4 );
    my $intelligence_scaled = ( ( $intelligence_mix * $self->level ) / 100 );
    return int( ( $intelligence_scaled + 5 ) * 1.1 );
}

sub resistance ($self) {
    my $races                = LasTres::Races->new;
    my $race                 = $self->race;
    my $resistance_base_race = $race->base_stats->resistance;
    my $resistance_born      = $self->born_stats->resistance;
    my $resistance_training  = $self->training_stats->resistance;
    my $resistance_mix =
      2 * $resistance_base_race +
      $resistance_born +
      ( $resistance_training / 4 );
    my $resistance_scaled = ( ( $resistance_mix * $self->level ) / 100 );
    return int( ( $resistance_scaled + 5 ) * 1.1 );
}

sub max_mana ($self) {
    my $races          = LasTres::Races->new;
    my $race           = $self->race;
    my $mana_base_race = $race->base_stats->mana;
    my $mana_born      = $self->born_stats->mana;
    my $mana_training  = $self->training_stats->mana;
    my $mana_mix    = 2 * $mana_base_race + $mana_born + ( $mana_training / 4 );
    my $mana_scaled = ( ( $mana_mix * $self->level ) / 100 );
    return int( $mana_scaled + $self->level + 10 );
}
1;
