package fr.umlv.poo.s5_a;

import java.util.Comparator;
import java.util.HashMap;
import java.util.Objects;
import java.util.PriorityQueue;

public interface Markets {
  public class Order {
    final long price;
    final String trader;
   
    Order(long price, String trader) {
      this.price = price;
      this.trader = Objects.requireNonNull(trader);
    }

    long getPrice() {
      return price;
    }
  }
 
  public class Stock {
    final PriorityQueue<Order> buyOrders;
    final PriorityQueue<Order> sellOrders;
   
    public Stock() {
      Comparator<Order> comparator = Comparator.comparing(Order::getPrice);
      this.buyOrders = new PriorityQueue<>(comparator);
      this.sellOrders = new PriorityQueue<>(comparator);
    }
  }
 
  public class StockExchange {
    private final HashMap<String, Stock> stockMap = new HashMap<>();
   
    public void createStock(String stockName) {
      Objects.requireNonNull(stockName);
      if (stockMap.containsKey(stockName)) {
        throw new IllegalStateException();
      }
      stockMap.put(stockName, new Stock());
    }
   
    private Stock getStock(String stockName) {
      Objects.requireNonNull(stockName);
      return stockMap.computeIfAbsent(stockName, key -> { throw new IllegalStateException(); });
    }
   
    public void buy(String stockName, long price, String trader) {
      getStock(stockName).buyOrders.offer(new Order(price, trader));
    }
   
    public void sell(String stockName, long price, String trader) {
      getStock(stockName).sellOrders.offer(new Order(price, trader));
    }
   
    public void resolveOrders() {
      stockMap.forEach((stockName, stock) -> {
        PriorityQueue<Order> sellOrders = stock.sellOrders;
        PriorityQueue<Order> buyOrders = stock.buyOrders;
        Order sellOrder = sellOrders.poll();
        Order buyOrder = buyOrders.poll();
        for(;;) {
          if (sellOrder == null) {
            while (buyOrder != null) {
              System.out.println("reject " + stockName + " buy order from " + buyOrder.trader + " at " + buyOrder.price);
              buyOrder = buyOrders.poll();
            }
            break;
          }
          if (buyOrder == null) {
            while (sellOrder != null) {
              System.out.println("reject " + stockName + " sell order from " + sellOrder.trader + " at " + sellOrder.price);
              sellOrder = sellOrders.poll();
            }
            break;
          }
          if (buyOrder.price >= sellOrder.price) {
            System.out.println("sell " + stockName + " from " + sellOrder.trader + " to " + buyOrder.trader + " at " + buyOrder.price);
            sellOrder = sellOrders.poll();
            buyOrder = buyOrders.poll();
            continue;
          }
          System.out.println("reject " + stockName + " buy order from " + buyOrder.trader + " at " + buyOrder.price);
          buyOrder = buyOrders.poll();
        }
      });
    }
  }
 
  public static void main(String[] args) {
    String boris = "boris";
    String jack = "jack";
   
    StockExchange exchange = new StockExchange();
    exchange.createStock("GOOGL");
    exchange.createStock("APPLE");
   
    exchange.buy("GOOGL", 10, boris);
    exchange.sell("GOOGL", 5, jack);
    exchange.sell("GOOGL", 7, jack);
   
    exchange.sell("APPLE", 10, boris);
    exchange.buy("APPLE", 11, jack);
    exchange.buy("APPLE", 8, jack);
   
    exchange.resolveOrders();
  }
}