/**
 * Grubtech Order Status Update - Java (Spring Boot)
 *
 * This example demonstrates how to update order status in Grubtech.
 *
 * Prerequisites:
 * - Java 17+
 * - Spring Boot 3.x
 * - Spring WebFlux (for WebClient)
 *
 * Replace the following placeholders:
 * - {{AUTH_TOKEN}}: Access token from authentication step
 * - {{ORDER_ID}}: The Grubtech order ID to update
 * - {{NEW_STATUS}}: The new status value
 */

package com.example.grubtech;

import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

@Service
public class GrubtechOrderStatusService {

    private static final String AUTH_TOKEN = "{{AUTH_TOKEN}}";
    private static final String BASE_URL = "https://api.staging.grubtech.io";

    private final WebClient webClient;

    /**
     * Valid order status values
     */
    public enum OrderStatus {
        ACCEPTED("accepted"),
        PREPARING("preparing"),
        READY("ready"),
        DELIVERED("delivered"),
        CANCELLED("cancelled");

        private final String value;

        OrderStatus(String value) {
            this.value = value;
        }

        public String getValue() {
            return value;
        }
    }

    public GrubtechOrderStatusService() {
        this.webClient = WebClient.builder()
                .baseUrl(BASE_URL)
                .build();
    }

    /**
     * Update order status in Grubtech
     *
     * @param orderId   The Grubtech order ID
     * @param newStatus The new status value
     * @param notes     Optional notes about the status change
     * @return Status update response
     */
    public StatusUpdateResponse updateOrderStatus(
            String orderId,
            OrderStatus newStatus,
            String notes
    ) {
        try {
            // Construct status update payload
            Map<String, Object> payload = new HashMap<>();
            payload.put("orderId", orderId);
            payload.put("status", newStatus.getValue());
            payload.put("timestamp", Instant.now().toString());

            if (notes != null && !notes.isEmpty()) {
                payload.put("notes", notes);
            }

            System.out.println("Updating order " + orderId + " to status: " + newStatus.getValue());

            // Make status update request
            StatusUpdateResponse response = webClient.put()
                    .uri("/v1/orders/" + orderId + "/status")
                    .header(HttpHeaders.AUTHORIZATION, "Bearer " + AUTH_TOKEN)
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                    .bodyValue(payload)
                    .retrieve()
                    .onStatus(
                            status -> !status.is2xxSuccessful(),
                            clientResponse -> clientResponse.bodyToMono(String.class)
                                    .flatMap(errorBody -> Mono.error(
                                            new RuntimeException(
                                                    "Status update failed: " +
                                                    clientResponse.statusCode() +
                                                    " - " + errorBody
                                            )
                                    ))
                    )
                    .bodyToMono(StatusUpdateResponse.class)
                    .block();

            if (response == null) {
                throw new RuntimeException("No response received from status update");
            }

            System.out.println("✅ Order status updated successfully!");
            System.out.println("Order ID: " + response.getOrderId());
            System.out.println("New Status: " + response.getStatus());
            System.out.println("Updated At: " + response.getUpdatedAt());

            return response;

        } catch (Exception e) {
            System.err.println("❌ Status update error: " + e.getMessage());
            throw e;
        }
    }

    /**
     * Example: Update order through typical workflow
     *
     * @param orderId The Grubtech order ID
     */
    public void orderWorkflowExample(String orderId) {
        try {
            // Step 1: Accept the order
            updateOrderStatus(orderId, OrderStatus.ACCEPTED, "Order confirmed");

            // Step 2: Start preparing
            updateOrderStatus(orderId, OrderStatus.PREPARING, "Chef started cooking");

            // Step 3: Mark as ready
            updateOrderStatus(orderId, OrderStatus.READY, "Order ready for pickup");

            // Step 4: Mark as delivered
            updateOrderStatus(orderId, OrderStatus.DELIVERED, "Order delivered to customer");

            System.out.println("✅ Order workflow completed!");

        } catch (Exception e) {
            System.err.println("❌ Workflow error: " + e.getMessage());

            // If something goes wrong, cancel the order
            updateOrderStatus(orderId, OrderStatus.CANCELLED, "Unable to fulfill order");
        }
    }

    /**
     * Response model for status update
     */
    public static class StatusUpdateResponse {
        private boolean success;
        private String orderId;
        private String status;
        private String updatedAt;
        private String message;

        // Getters and setters
        public boolean isSuccess() { return success; }
        public void setSuccess(boolean success) { this.success = success; }

        public String getOrderId() { return orderId; }
        public void setOrderId(String orderId) { this.orderId = orderId; }

        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }

        public String getUpdatedAt() { return updatedAt; }
        public void setUpdatedAt(String updatedAt) { this.updatedAt = updatedAt; }

        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
    }

    // Main method for testing
    public static void main(String[] args) {
        try {
            GrubtechOrderStatusService service = new GrubtechOrderStatusService();

            String orderId = "{{ORDER_ID}}";
            OrderStatus newStatus = OrderStatus.PREPARING; // Change to {{NEW_STATUS}}

            // Single status update
            service.updateOrderStatus(orderId, newStatus, "Status update from POS");

            // Or run through full workflow
            // service.orderWorkflowExample(orderId);

        } catch (Exception e) {
            System.exit(1);
        }
    }
}
