package AITB_2022.extaction;

import adf.core.agent.communication.MessageManager;
import adf.core.agent.develop.DevelopData;
import adf.core.agent.info.*;
import adf.core.agent.module.ModuleManager;
import adf.core.agent.precompute.PrecomputeData;
import adf.core.component.module.AbstractModule;
import java.util.*;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.standard.entities.*;

import static rescuecore2.standard.entities.StandardEntityURN.REFUGE;

/**
 * RefugeSelector specifies the destination for injured civilian.
 * The result is Refuge class.
 */
public class RefugeSelector extends AbstractRefugeSelector {
    public RefugeSelector(AgentInfo ai, WorldInfo wi, ScenarioInfo si,
            ModuleManager moduleManager, DevelopData developData) {
        super(ai, wi, si, moduleManager, developData);
    }

    @Override
    public AbstractModule precompute(PrecomputeData pd) {
        super.precompute(pd);
        if (this.getCountPrecompute() > 1)
            return this;

        return this;
    }

    @Override
    public AbstractModule resume(PrecomputeData pd) {
        super.resume(pd);
        if (this.getCountResume() > 1)
            return this;

        return this;
    }

    @Override
    public AbstractModule preparate() {
        super.preparate();
        if (this.getCountPreparate() > 1)
            return this;

        return this;
    }

    @Override
    public AbstractModule updateInfo(MessageManager mm) {
        return this;
    }

    @Override
    public AbstractModule calc() {
        /* 初期化設定 */
        // RefugeのIDを取得する．
        Collection<StandardEntity> refuges = this.worldInfo.getEntitiesOfType(REFUGE);
        EntityID me = this.agentInfo.getID();
        EntityID nearestID = null;
        List<EntityID> nearestsID = new ArrayList<>();
        List<EntityID> minwaitingBedID = new ArrayList<>();
        int dis_time, nearest = 500, nearestBeds = 500, minwaitingBed = 100;

        for (StandardEntity En : refuges) {
            Refuge refuge = (Refuge) En;
            EntityID id = En.getID();
            // Refugeまで直線の距離
            double distance = this.worldInfo.getDistance(me, id);
            // 救急エージェントが約1ステップで移動する距離（7000)
            // Refugeまで何ステップで移動できるか
            dis_time = (int) (distance / 7000);

            // Refugeの空き待ち人数
            int waitingListSize = refuge.getWaitingListSize();
            // Refugeのベッドの総数
            int bedCapacity = refuge.getBedCapacity();
            // Refugeのベッドの占有数
            int occupiedBed = refuge.getOccupiedBeds();

            // Refugeの空き待ち人数がない，かつベッドの占有数が最大ではない場合
            if (waitingListSize == 0 && bedCapacity != occupiedBed) {
                // 一番ステップ数が少ないRefuge
                if (dis_time < nearest) {
                    nearestsID.clear();
                    nearestsID.add(id);
                    nearest = dis_time;
                }
                if (dis_time <= nearest) {
                    nearestsID.add(id);
                    nearest = dis_time;
                }
            } else {
                // 空き待ち人数が少ないRefuge
                if (waitingListSize < minwaitingBed) {
                    minwaitingBedID.clear();
                    minwaitingBedID.add(id);
                    minwaitingBed = waitingListSize;
                }
                if (waitingListSize <= minwaitingBed) {
                    minwaitingBedID.add(id);
                    minwaitingBed = waitingListSize;
                }
            }
        }

        // すべてのRefugeが空き待ち人がいる場合
        // 最も空き待ち人数が少ない場所へ
        if (nearest == 500) {
            for (EntityID n : minwaitingBedID) {
                double distance = this.worldInfo.getDistance(me, n);
                dis_time = (int) (distance / 7000);
                if (dis_time < nearest) {
                    nearestsID.clear();
                    nearestsID.add(n);
                    nearest = dis_time;
                }
                if (dis_time <= nearest) {
                    nearestsID.add(n);
                    nearest = dis_time;
                }
            }
        }

        // 最もベッドの占有数が少ないRefugeへ
        for (EntityID n : nearestsID) {
            StandardEntity En = this.worldInfo.getEntity(n);
            Refuge refuge = (Refuge) En;
            int occupiedBeds = refuge.getOccupiedBeds();
            if (occupiedBeds < nearestBeds) {
                nearestBeds = occupiedBeds;
                nearestID = n;
            }
        }

        StandardEntity En = this.worldInfo.getEntity(nearestID);
        Refuge refuge = (Refuge) En;
        this.result = refuge;
        // RefugeをResultに送る．
        return this;
    }
}
