package tc.oc.api.docs.virtual;

import java.util.Collection;
import java.util.Set;
import javax.annotation.Nullable;

import java.time.Instant;
import tc.oc.api.annotations.Serialize;
import tc.oc.api.model.ModelName;

@Serialize
@ModelName(value = "Match", plural = "matches")
public interface MatchDoc extends Model {
    String server_id();
    String family_id();

    // Can be null if doc was generated by the API and the map is not in the DB
    MapDoc map();
    Collection<? extends Team> competitors();
    Collection<? extends Goal> objectives();

    Instant load();
    @Nullable Instant start();
    @Nullable Instant end();
    @Nullable Instant unload();

    boolean join_mid_match();
    int player_count();

    Collection<String> winning_team_ids();
    Collection<String> winning_user_ids();

    Set<String> mutations();

    @Serialize
    interface Team extends MapDoc.Team, CompetitorDoc {
        @Nullable Integer size(); // Shouldn't be nullable, but data is missing in some old match documents
        String league_team_id();
    }

    @Serialize
    interface Goal extends Model {
        String type();
        String name();
    }

    @Serialize
    interface OwnedGoal extends Goal {
        @Nullable String owner_id();
        @Nullable String owner_name();
    }

    @Serialize
    interface IncrementalGoal extends Goal {
        double completion();
    }

    @Serialize
    interface TouchableGoal extends OwnedGoal {
        Collection<? extends Proximity> proximities();

        @Serialize
        interface Proximity extends Model {
            boolean touched();
            @Nullable Metric metric();
            double distance();

            enum Metric {
                CLOSEST_PLAYER, CLOSEST_PLAYER_HORIZONTAL,
                CLOSEST_BLOCK, CLOSEST_BLOCK_HORIZONTAL,
                CLOSEST_KILL, CLOSEST_KILL_HORIZONTAL;
            }
        }
    }

    @Serialize
    interface Destroyable extends TouchableGoal, IncrementalGoal {
        int total_blocks();
        int breaks_required();
        int breaks();
    }
}
