package com.yourname.premiumah.manager;

import com.yourname.premiumah.model.Listing;
import com.yourname.premiumah.model.ListingStatus;
import com.yourname.premiumah.model.SortMode;
import com.yourname.premiumah.storage.StorageManager;
import org.bukkit.Material;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;

public final class ListingManager {
    private final StorageManager storageManager;
    private final Map<String, Listing> listings = new LinkedHashMap<>();

    public ListingManager(StorageManager storageManager) {
        this.storageManager = storageManager;
    }

    public synchronized void loadFromStorage() {
        listings.clear();
        listings.putAll(storageManager.listingsSnapshot());
    }

    public synchronized void saveToStorage() {
        storageManager.replaceListings(listings);
    }

    public synchronized void clear() {
        listings.clear();
    }

    public synchronized Optional<Listing> get(String id) {
        if (id == null) {
            return Optional.empty();
        }
        return Optional.ofNullable(listings.get(id.toUpperCase()));
    }

    public synchronized boolean contains(String id) {
        return listings.containsKey(id.toUpperCase());
    }

    public synchronized void add(Listing listing) {
        listings.put(listing.id(), listing);
    }

    public synchronized Collection<Listing> all() {
        return new ArrayList<>(listings.values());
    }

    public synchronized List<Listing> activeListings(SortMode sortMode, Material filter) {
        long now = System.currentTimeMillis();
        return listings.values().stream()
                .filter(listing -> listing.isActive(now))
                .filter(listing -> filter == null || listing.rawItem().getType() == filter)
                .sorted(comparator(sortMode))
                .collect(Collectors.toList());
    }

    public synchronized List<Listing> activeListingsBySeller(UUID sellerUuid, SortMode sortMode) {
        long now = System.currentTimeMillis();
        return listings.values().stream()
                .filter(listing -> listing.sellerUuid().equals(sellerUuid))
                .filter(listing -> listing.isActive(now))
                .sorted(comparator(sortMode))
                .collect(Collectors.toList());
    }

    public synchronized List<Listing> activeListingsBySellerName(String sellerName, SortMode sortMode) {
        long now = System.currentTimeMillis();
        String normalized = sellerName == null ? "" : sellerName.toLowerCase();
        return listings.values().stream()
                .filter(listing -> listing.sellerName().toLowerCase().equals(normalized))
                .filter(listing -> listing.isActive(now))
                .sorted(comparator(sortMode))
                .collect(Collectors.toList());
    }

    public synchronized int activeCount(UUID sellerUuid) {
        long now = System.currentTimeMillis();
        return (int) listings.values().stream()
                .filter(listing -> listing.sellerUuid().equals(sellerUuid))
                .filter(listing -> listing.isActive(now))
                .count();
    }

    public synchronized List<Listing> expiredActiveListings(long now) {
        return listings.values().stream()
                .filter(listing -> listing.status() == ListingStatus.ACTIVE)
                .filter(listing -> listing.expiresAt() <= now)
                .collect(Collectors.toList());
    }

    private Comparator<Listing> comparator(SortMode sortMode) {
        return switch (sortMode == null ? SortMode.NEWEST : sortMode) {
            case OLDEST -> Comparator.comparingLong(Listing::createdAt);
            case LOWEST_PRICE -> Comparator.comparingDouble(Listing::price).thenComparing(Comparator.comparingLong(Listing::createdAt).reversed());
            case HIGHEST_PRICE -> Comparator.comparingDouble(Listing::price).reversed().thenComparing(Comparator.comparingLong(Listing::createdAt).reversed());
            case NEWEST -> Comparator.comparingLong(Listing::createdAt).reversed();
        };
    }
}
