package com.aps.demo;

import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Algorithm.GAScheduleResult;
import com.aps.entity.Algorithm.IDAndChildID.GroupResult;
import com.aps.entity.Algorithm.IDAndChildID.NodeInfo;
import com.aps.entity.basic.Entry;
import com.aps.entity.basic.Order;
import com.aps.service.Algorithm.IdGroupingWithDualSerial;
import com.aps.service.Algorithm.ScheduleOperationService;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

import static org.junit.jupiter.api.Assertions.assertEquals;

class AutoInsertProtectionTest {

    @Test
    void frozenResultIsPinnedBeforeAutoInsertRedecode() {
        LocalDateTime baseTime = LocalDateTime.of(2026, 5, 1, 0, 0);
        Chromosome chromosome = new Chromosome();
        chromosome.setBaseTime(baseTime);

        Entry frozenEntry = new Entry();
        frozenEntry.setId(10);
        chromosome.setAllOperations(new CopyOnWriteArrayList<>(Arrays.asList(frozenEntry)));

        GAScheduleResult frozenResult = new GAScheduleResult();
        frozenResult.setOperationId(10);
        frozenResult.setMachineId(31L);
        frozenResult.setStartTime(3600);

        GAScheduleResult futureResult = new GAScheduleResult();
        futureResult.setOperationId(11);
        futureResult.setMachineId(32L);
        futureResult.setStartTime(20000);
        chromosome.setResult(new CopyOnWriteArrayList<>(Arrays.asList(frozenResult, futureResult)));

        ScheduleOperationService service = new ScheduleOperationService(null, null);
        ReflectionTestUtils.invokeMethod(service, "pinFrozenResults", chromosome, baseTime.plusSeconds(10000));

        assertEquals(1, frozenResult.getLockStartTime());
        assertEquals(3600, frozenResult.getDesignatedStartTime());
        assertEquals(Long.valueOf(31L), frozenResult.getForcedMachineId());
        assertEquals(baseTime.plusSeconds(3600), frozenEntry.getDesignatedStartTime());
        assertEquals(0, futureResult.getLockStartTime());
    }

    @Test
    void autoInsertOperationIdsStartAfterExistingChromosomeOperations() {
        NodeInfo existingNode = new NodeInfo("old", 3, 1, new ArrayList<>(), new ArrayList<>());
        List<GroupResult> relations = new ArrayList<>(Collections.singletonList(
                new GroupResult(new ArrayList<>(Collections.singletonList(existingNode)), new HashMap<>())));

        List<GroupResult> updated = IdGroupingWithDualSerial.addNewDataWithIsolatedGroup(
                relations,
                Collections.singletonList("new"),
                Collections.singletonList(""),
                12);

        GroupResult insertedGroup = updated.get(updated.size() - 1);
        assertEquals(Integer.valueOf(12), insertedGroup.getNodeInfoList().get(0).getGlobalSerial());
    }

    @Test
    void autoInsertGroupIdStartsAfterExistingOrderEntryAndResultGroups() {
        Chromosome chromosome = new Chromosome();

        Order order = new Order();
        order.setId(3);
        chromosome.setOrders(new CopyOnWriteArrayList<>(Collections.singletonList(order)));

        Entry entry = new Entry();
        entry.setGroupId(4);
        chromosome.setAllOperations(new CopyOnWriteArrayList<>(Collections.singletonList(entry)));

        GAScheduleResult result = new GAScheduleResult();
        result.setGroupId(4);
        chromosome.setResult(new CopyOnWriteArrayList<>(Collections.singletonList(result)));

        chromosome.setOperatRel(new CopyOnWriteArrayList<>(Collections.singletonList(
                new GroupResult(new ArrayList<>(), new HashMap<>()))));

        ScheduleOperationService service = new ScheduleOperationService(null, null);
        Integer nextGroupId = ReflectionTestUtils.invokeMethod(service, "resolveNextAutoInsertGroupId", chromosome);
        ReflectionTestUtils.invokeMethod(service, "padOperationRelations", chromosome.getOperatRel(), nextGroupId);

        assertEquals(Integer.valueOf(5), nextGroupId);
        assertEquals(4, chromosome.getOperatRel().size());
    }

}
