package auctiora;

import jakarta.inject.Inject;
import jakarta.ws.rs.*;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.jboss.logging.Logger;

import java.util.HashMap;
import java.util.Map;

/**
 * REST API for Auction Monitor control and status.
 * Provides endpoints for:
 * - Status checking
 * - Manual workflow triggers
 * - Statistics
 */
@Path("/api/monitor")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
public class AuctionMonitorResource {
   
   private static final Logger LOG = Logger.getLogger(AuctionMonitorResource.class);
   
   @Inject
   DatabaseService db;
   
   @Inject
   QuarkusWorkflowScheduler scheduler;
   
   @Inject
   NotificationService notifier;
   
   @Inject
   RateLimitedHttpClient httpClient;
   
   /**
    * GET /api/monitor/status
    * Returns current monitoring status
    */
   @GET
   @Path("/status")
   public Response getStatus() {
      try {
         Map<String, Object> status = new HashMap<>();
         status.put("running", true);
         status.put("auctions", db.getAllAuctions().size());
         status.put("lots", db.getAllLots().size());
         status.put("images", db.getImageCount());
         
         // Count closing soon
         var closingSoon = 0;
         for (var lot : db.getAllLots()) {
            if (lot.closingTime() != null && lot.minutesUntilClose() < 30) {
               closingSoon++;
            }
         }
         status.put("closingSoon", closingSoon);
         
         return Response.ok(status).build();
         
      } catch (Exception e) {
         LOG.error("Failed to get status", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * GET /api/monitor/statistics
    * Returns detailed statistics
    */
   @GET
   @Path("/statistics")
   public Response getStatistics() {
      try {
         Map<String, Object> stats = new HashMap<>();
         
         var auctions = db.getAllAuctions();
         var lots     = db.getAllLots();
         
         stats.put("totalAuctions", auctions.size());
         stats.put("totalLots", lots.size());
         stats.put("totalImages", db.getImageCount());
         
         // Lot statistics
         var    activeLots   = 0;
         var    lotsWithBids = 0;
         double totalBids    = 0;
         
         for (var lot : lots) {
            if (lot.closingTime() != null && lot.minutesUntilClose() > 0) {
               activeLots++;
            }
            if (lot.currentBid() > 0) {
               lotsWithBids++;
               totalBids += lot.currentBid();
            }
         }
         
         stats.put("activeLots", activeLots);
         stats.put("lotsWithBids", lotsWithBids);
         stats.put("totalBidValue", String.format("€%.2f", totalBids));
         stats.put("averageBid", lotsWithBids > 0 ? String.format("€%.2f", totalBids / lotsWithBids) : "€0.00");
         
         return Response.ok(stats).build();
         
      } catch (Exception e) {
         LOG.error("Failed to get statistics", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * POST /api/monitor/trigger/scraper-import
    * Manually trigger scraper import workflow
    */
   @POST
   @Path("/trigger/scraper-import")
   public Response triggerScraperImport() {
      try {
         scheduler.importScraperData();
         return Response.ok(Map.of("message", "Scraper import triggered successfully")).build();
      } catch (Exception e) {
         LOG.error("Failed to trigger scraper import", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * POST /api/monitor/trigger/image-processing
    * Manually trigger image processing workflow
    */
   @POST
   @Path("/trigger/image-processing")
   public Response triggerImageProcessing() {
      try {
         scheduler.processImages();
         return Response.ok(Map.of("message", "Image processing triggered successfully")).build();
      } catch (Exception e) {
         LOG.error("Failed to trigger image processing", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * POST /api/monitor/trigger/bid-monitoring
    * Manually trigger bid monitoring workflow
    */
   @POST
   @Path("/trigger/bid-monitoring")
   public Response triggerBidMonitoring() {
      try {
         scheduler.monitorBids();
         return Response.ok(Map.of("message", "Bid monitoring triggered successfully")).build();
      } catch (Exception e) {
         LOG.error("Failed to trigger bid monitoring", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * POST /api/monitor/trigger/closing-alerts
    * Manually trigger closing alerts workflow
    */
   @POST
   @Path("/trigger/closing-alerts")
   public Response triggerClosingAlerts() {
      try {
         scheduler.checkClosingTimes();
         return Response.ok(Map.of("message", "Closing alerts triggered successfully")).build();
      } catch (Exception e) {
         LOG.error("Failed to trigger closing alerts", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * GET /api/monitor/auctions
    * Returns list of all auctions
    */
   @GET
   @Path("/auctions")
   public Response getAuctions(@QueryParam("country") String country) {
      try {
         var auctions = country != null && !country.isEmpty()
                        ? db.getAuctionsByCountry(country)
                        : db.getAllAuctions();
         
         return Response.ok(auctions).build();
      } catch (Exception e) {
         LOG.error("Failed to get auctions", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * GET /api/monitor/lots
    * Returns list of active lots
    */
   @GET
   @Path("/lots")
   public Response getActiveLots() {
      try {
         var lots = db.getActiveLots();
         return Response.ok(lots).build();
      } catch (Exception e) {
         LOG.error("Failed to get lots", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * GET /api/monitor/lots/closing-soon
    * Returns lots closing within specified minutes (default 30)
    */
   @GET
   @Path("/lots/closing-soon")
   public Response getLotsClosingSoon(@QueryParam("minutes") @DefaultValue("30") int minutes) {
      try {
         var allLots = db.getActiveLots();
         var closingSoon = allLots.stream()
                                  .filter(lot -> lot.closingTime() != null && lot.minutesUntilClose() < minutes)
                                  .toList();
         
         return Response.ok(closingSoon).build();
      } catch (Exception e) {
         LOG.error("Failed to get closing lots", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * GET /api/monitor/lots/{lotId}/images
    * Returns images for a specific lot
    */
   @GET
   @Path("/lots/{lotId}/images")
   public Response getLotImages(@PathParam("lotId") int lotId) {
      try {
         var images = db.getImagesForLot(lotId);
         return Response.ok(images).build();
      } catch (Exception e) {
         LOG.error("Failed to get lot images", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * POST /api/monitor/test-notification
    * Send a test notification
    */
   @POST
   @Path("/test-notification")
   public Response sendTestNotification(Map<String, String> request) {
      try {
         var message  = request.getOrDefault("message", "Test notification from Auction Monitor");
         var title    = request.getOrDefault("title", "Test Notification");
         var priority = Integer.parseInt(request.getOrDefault("priority", "0"));
         
         notifier.sendNotification(message, title, priority);
         
         return Response.ok(Map.of("message", "Test notification sent successfully")).build();
      } catch (Exception e) {
         LOG.error("Failed to send test notification", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * GET /api/monitor/rate-limit/stats
    * Returns HTTP rate limiting statistics for all hosts
    */
   @GET
   @Path("/rate-limit/stats")
   public Response getRateLimitStats() {
      try {
         var stats = httpClient.getAllStats();
         
         Map<String, Object> response = new HashMap<>();
         response.put("hosts", stats.size());
         
         Map<String, Object> hostStats = new HashMap<>();
         for (var entry : stats.entrySet()) {
            var stat = entry.getValue();
            hostStats.put(entry.getKey(), Map.of(
                    "totalRequests", stat.getTotalRequests(),
                    "successfulRequests", stat.getSuccessfulRequests(),
                    "failedRequests", stat.getFailedRequests(),
                    "rateLimitedRequests", stat.getRateLimitedRequests(),
                    "averageDurationMs", stat.getAverageDurationMs()
                                                ));
         }
         response.put("statistics", hostStats);
         
         return Response.ok(response).build();
         
      } catch (Exception e) {
         LOG.error("Failed to get rate limit stats", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
   
   /**
    * GET /api/monitor/rate-limit/stats/{host}
    * Returns HTTP rate limiting statistics for a specific host
    */
   @GET
   @Path("/rate-limit/stats/{host}")
   public Response getRateLimitStatsForHost(@PathParam("host") String host) {
      try {
         var stat = httpClient.getStats(host);
         
         if (stat == null) {
            return Response.status(Response.Status.NOT_FOUND)
                           .entity(Map.of("error", "No statistics found for host: " + host))
                           .build();
         }
         
         Map<String, Object> response = Map.of(
                 "host", stat.getHost(),
                 "totalRequests", stat.getTotalRequests(),
                 "successfulRequests", stat.getSuccessfulRequests(),
                 "failedRequests", stat.getFailedRequests(),
                 "rateLimitedRequests", stat.getRateLimitedRequests(),
                 "averageDurationMs", stat.getAverageDurationMs()
                                              );
         
         return Response.ok(response).build();
         
      } catch (Exception e) {
         LOG.error("Failed to get rate limit stats for host", e);
         return Response.status(Response.Status.INTERNAL_SERVER_ERROR)
                        .entity(Map.of("error", e.getMessage()))
                        .build();
      }
   }
}
