/**
 * Grubtech Menu Sync - Java (Spring Boot)
 *
 * This example demonstrates how to push menu data to Grubtech API.
 *
 * Prerequisites:
 * - Java 17+
 * - Spring Boot 3.x
 * - Spring WebFlux (for WebClient)
 *
 * Replace the following placeholders:
 * - {{AUTH_TOKEN}}: Access token from authentication step
 * - {{MENU_DATA}}: Your menu data in the required format
 */

package com.example.grubtech;

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

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class GrubtechMenuSync {

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

    private final WebClient webClient;

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

    /**
     * Push menu data to Grubtech API
     *
     * @param menuData Menu data object
     * @return Menu ID from response
     */
    public String createMenu(MenuData menuData) {
        try {
            // Validate menu data
            if (menuData.getCategories() == null || menuData.getCategories().isEmpty()) {
                throw new IllegalArgumentException("Menu must have at least one category");
            }

            // Make menu creation request
            MenuResponse response = webClient.post()
                    .uri("/v1/menus")
                    .header(HttpHeaders.AUTHORIZATION, "Bearer " + AUTH_TOKEN)
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                    .bodyValue(menuData)
                    .retrieve()
                    .onStatus(
                            status -> !status.is2xxSuccessful(),
                            clientResponse -> clientResponse.bodyToMono(String.class)
                                    .flatMap(errorBody -> Mono.error(
                                            new RuntimeException(
                                                    "Menu creation failed: " +
                                                    clientResponse.statusCode() +
                                                    " - " + errorBody
                                            )
                                    ))
                    )
                    .bodyToMono(MenuResponse.class)
                    .block();

            if (response == null || response.getMenuId() == null) {
                throw new RuntimeException("No menu ID received from response");
            }

            System.out.println("✅ Menu created successfully!");
            System.out.println("Menu ID: " + response.getMenuId());
            System.out.println("Status: " + response.getStatus());

            return response.getMenuId();

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

    /**
     * Update existing menu
     *
     * @param menuId   ID of the menu to update
     * @param menuData Updated menu data
     */
    public void updateMenu(String menuId, MenuData menuData) {
        try {
            webClient.put()
                    .uri("/v1/menus/" + menuId)
                    .header(HttpHeaders.AUTHORIZATION, "Bearer " + AUTH_TOKEN)
                    .header(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE)
                    .bodyValue(menuData)
                    .retrieve()
                    .onStatus(
                            status -> !status.is2xxSuccessful(),
                            clientResponse -> Mono.error(
                                    new RuntimeException("Menu update failed: " + clientResponse.statusCode())
                            )
                    )
                    .toBodilessEntity()
                    .block();

            System.out.println("✅ Menu updated successfully!");

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

    /**
     * Create example menu data
     */
    private static MenuData createExampleMenuData() {
        MenuData menu = new MenuData();
        menu.setName("Restaurant Menu");
        menu.setDescription("Main menu with categories and items");

        List<MenuCategory> categories = new ArrayList<>();

        // Appetizers category
        MenuCategory appetizers = new MenuCategory();
        appetizers.setId("cat-1");
        appetizers.setName("Appetizers");
        appetizers.setDescription("Start your meal right");
        appetizers.setSortOrder(1);

        MenuItem springRolls = new MenuItem();
        springRolls.setId("item-1");
        springRolls.setName("Spring Rolls");
        springRolls.setDescription("Crispy vegetable spring rolls");
        springRolls.setPrice(8.99);
        springRolls.setAvailable(true);

        Modifier extraSauce = new Modifier();
        extraSauce.setId("mod-1");
        extraSauce.setName("Extra Sauce");
        extraSauce.setPrice(1.50);
        extraSauce.setAvailable(true);

        springRolls.setModifiers(List.of(extraSauce));
        appetizers.setItems(List.of(springRolls));

        // Main courses category
        MenuCategory mainCourses = new MenuCategory();
        mainCourses.setId("cat-2");
        mainCourses.setName("Main Courses");
        mainCourses.setDescription("Delicious entrees");
        mainCourses.setSortOrder(2);

        MenuItem chicken = new MenuItem();
        chicken.setId("item-2");
        chicken.setName("Grilled Chicken");
        chicken.setDescription("Tender chicken with herbs");
        chicken.setPrice(15.99);
        chicken.setAvailable(true);
        chicken.setModifiers(new ArrayList<>());

        mainCourses.setItems(List.of(chicken));

        categories.add(appetizers);
        categories.add(mainCourses);
        menu.setCategories(categories);

        return menu;
    }

    // Data models
    public static class MenuData {
        private String name;
        private String description;
        private List<MenuCategory> categories;

        // Getters and setters
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        public List<MenuCategory> getCategories() { return categories; }
        public void setCategories(List<MenuCategory> categories) { this.categories = categories; }
    }

    public static class MenuCategory {
        private String id;
        private String name;
        private String description;
        private int sortOrder;
        private List<MenuItem> items;

        // Getters and setters omitted for brevity
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        public int getSortOrder() { return sortOrder; }
        public void setSortOrder(int sortOrder) { this.sortOrder = sortOrder; }
        public List<MenuItem> getItems() { return items; }
        public void setItems(List<MenuItem> items) { this.items = items; }
    }

    public static class MenuItem {
        private String id;
        private String name;
        private String description;
        private double price;
        private boolean available;
        private List<Modifier> modifiers;

        // Getters and setters omitted for brevity
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public String getDescription() { return description; }
        public void setDescription(String description) { this.description = description; }
        public double getPrice() { return price; }
        public void setPrice(double price) { this.price = price; }
        public boolean isAvailable() { return available; }
        public void setAvailable(boolean available) { this.available = available; }
        public List<Modifier> getModifiers() { return modifiers; }
        public void setModifiers(List<Modifier> modifiers) { this.modifiers = modifiers; }
    }

    public static class Modifier {
        private String id;
        private String name;
        private double price;
        private boolean available;

        // Getters and setters omitted for brevity
        public String getId() { return id; }
        public void setId(String id) { this.id = id; }
        public String getName() { return name; }
        public void setName(String name) { this.name = name; }
        public double getPrice() { return price; }
        public void setPrice(double price) { this.price = price; }
        public boolean isAvailable() { return available; }
        public void setAvailable(boolean available) { this.available = available; }
    }

    public static class MenuResponse {
        private String menuId;
        private String status;
        private String message;

        // Getters and setters
        public String getMenuId() { return menuId; }
        public void setMenuId(String menuId) { this.menuId = menuId; }
        public String getStatus() { return status; }
        public void setStatus(String status) { this.status = status; }
        public String getMessage() { return message; }
        public void setMessage(String message) { this.message = message; }
    }

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

            // Create example menu data
            MenuData menuData = createExampleMenuData();

            // Create menu
            String menuId = menuSync.createMenu(menuData);

            // Optionally update the menu
            // menuSync.updateMenu(menuId, menuData);

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