package LasTres::Location;

use v5.36.0;

use strict;
use warnings;

use feature 'signatures';

use LasTres::Planets;
use Moo::Role;

use JSON qw/to_json/;

requires qw/identifier name description parent actions npcs/;

my $planets = LasTres::Planets->new;

sub show_intro ( $self, $pj ) {
    $pj->append_log_line(
        [
            { text  => 'Estas en ' },
            { color => 'red', text => $self->parent->name },
            { text  => '/' },
            { color => 'green', text => $self->name },
        ]
    );
    $pj->append_log_line( [ { text => $pj->location->description }, ] );
}

sub notify_arrival($self, $team) {
    require LasTres::Redis;
    my $redis = LasTres::Redis->new;
    for my $pj ($team->members) {
        $self->show_intro($pj);
        $redis->publish( $redis->pj_subscription($pj), to_json({ command => 'update-location' }));
    }
}

sub place_team($self, $team) {
    $team->location($self);
    $team->update;
    $self->notify_arrival($team);
}

sub to_json_array ($self) {
    my $hash = $self->hash;
    return to_json(
        [
            $hash->{planet}{identifier}, $hash->{super_area}{identifier},
            $hash->{area}{identifier},   $hash->{location}{identifier}
        ]
    );
}

sub is_connected_by_move ( $self, $otherLocation, $pj = undef ) {
    if ( !defined $otherLocation ) {
        die '$otherLocation must be defined in is_connected.';
    }
    my $json_array_other_location = $otherLocation->to_json_array;
    if ( grep { $_->to_json_array eq $json_array_other_location }
        @{ $self->get_available_locations_to_move_to($pj) } )
    {
        return 1;
    }
    return 0;
}

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

    my $connected_places = [];
    if ( $location->can('connected_places') ) {
        @$connected_places = ( @{ $team->location->connected_places } );
    }
    @$connected_places =
      ( @$connected_places, @{ $location->parent->children } );
    @$connected_places =
      grep { $_->identifier ne $location->identifier } @$connected_places;
    return $connected_places;
}

sub get ( $planet_id, $super_area_id, $area_id, $location_id ) {
    my $planet = $planets->hash->{$planet_id};
    if ( !defined $planet ) {
        die "No such planet $planet_id.";
    }
    my $super_area = $planet->super_areas->{$super_area_id};
    if ( !defined $super_area ) {
        die "No such super_area $super_area_id in planet $planet_id.";
    }
    my $area = $super_area->areas->{$area_id};
    if ( !defined $area ) {
        die
"No such area $area_id in super_area $super_area_id in planet $planet_id.";
    }
    my $location = $area->locations->{$location_id};
    if ( !defined $location ) {
        die
"No such location $location_id in area $area_id in super_area $super_area_id in planet $planet_id.";

    }
    return $location;
}

sub hash ($self) {
    my $location = $self;
    if ( !Moo::Role::does_role( $location, 'LasTres::Location' ) ) {
        die "$location does not implement LasTres::Location.";
    }
    my $area = $location->parent;
    if ( !Moo::Role::does_role( $area, 'LasTres::Area' ) ) {
        die "$area does not implement LasTres::Area.";
    }
    my $super_area = $area->parent;
    if ( !Moo::Role::does_role( $super_area, 'LasTres::SuperArea' ) ) {
        die "$super_area does not implement LasTres::SuperArea.";
    }
    my $planet = $super_area->parent;
    if ( !Moo::Role::does_role( $planet, 'LasTres::Planet' ) ) {
        die "$planet does not implement LasTres::Planet.";
    }
    return {
        planet => {
            name       => $planet->name,
            identifier => $planet->identifier,
        },
        super_area => {
            name       => $super_area->name,
            identifier => $super_area->identifier,
        },
        area => {
            name       => $area->name,
            identifier => $area->identifier,
        },
        location => {
            name       => $location->name,
            identifier => $location->identifier,
        },
    };
}
1;
