package com.alttd.altitudeweb.mappers;

import com.alttd.altitudeweb.database.luckperms.PlayerWithGroup;
import com.alttd.altitudeweb.database.proxyplaytime.StaffPt;
import com.alttd.altitudeweb.model.StaffPlaytimeDto;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
public final class StaffPtToStaffPlaytimeMapper {
    private record PlaytimeInfo(long totalPlaytime, long lastPlayed) {}

    public List<StaffPlaytimeDto> map(List<StaffPt> sessions, List<PlayerWithGroup> staffMembers, long from, long to, HashMap<String, String> staffGroupsMap) {
        Map<UUID, PlaytimeInfo> playtimeData = getUuidPlaytimeInfoMap(sessions, from, to);

        for (PlayerWithGroup staffMember : staffMembers) {
            if (!playtimeData.containsKey(staffMember.uuid())) {
                playtimeData.put(staffMember.uuid(), new PlaytimeInfo(0L, Long.MIN_VALUE));
            }
        }

        List<StaffPlaytimeDto> results = new ArrayList<>(playtimeData.size());
        for (Map.Entry<UUID, PlaytimeInfo> entry : playtimeData.entrySet()) {
            long lastPlayedMillis = entry.getValue().lastPlayed() == Long.MIN_VALUE ? 0L : entry.getValue().lastPlayed();
            StaffPlaytimeDto dto = new StaffPlaytimeDto();
            Optional<PlayerWithGroup> first = staffMembers.stream()
                    .filter(player -> player.uuid().equals(entry.getKey())).findFirst();
            dto.setStaffMember(first.isPresent() ? first.get().username() : entry.getKey().toString());
            dto.setStaffMember(staffMembers.stream()
                                       .filter(player -> player.uuid().equals(entry.getKey()))
                                       .map(PlayerWithGroup::username)
                                       .findFirst()
                                       .orElse(entry.getKey().toString())
                              );
            dto.setLastPlayed(OffsetDateTime.ofInstant(Instant.ofEpochMilli(lastPlayedMillis), ZoneOffset.UTC));
            dto.setPlaytime((int) TimeUnit.MILLISECONDS.toMinutes(entry.getValue().totalPlaytime()));
            if (first.isPresent()) {
                dto.setRole(staffGroupsMap.getOrDefault(first.get().group(), "Unknown"));
            } else {
                dto.setRole("Unknown");
            }
            results.add(dto);
        }
        return results;
    }

    private Map<UUID, PlaytimeInfo> getUuidPlaytimeInfoMap(List<StaffPt> sessions, long from, long to) {
        Map<UUID, PlaytimeInfo> playtimeData = new HashMap<>();
        for (StaffPt session : sessions) {
            long overlapStart = Math.max(session.sessionStart(), from);
            long overlapEnd = Math.min(session.sessionEnd(), to);
            if (overlapEnd <= overlapStart) {
                continue;
            }

            PlaytimeInfo info = playtimeData.getOrDefault(session.uuid(), new PlaytimeInfo(0L, Long.MIN_VALUE));
            long totalPlaytime = info.totalPlaytime() + (overlapEnd - overlapStart);
            long lastPlayed = Math.max(info.lastPlayed(), overlapEnd);
            playtimeData.put(session.uuid(), new PlaytimeInfo(totalPlaytime, lastPlayed));
        }
        return playtimeData;
    }
}


