package de.avatic.lcc.controller.maps;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.time.Instant;

/**
 * REST Controller für Azure Maps mit Entra ID Integration
 */
@RestController
@RequestMapping("/api/maps")
@CrossOrigin(origins = {"http://localhost:3000", "http://localhost:8080", "https://yourdomain.com"})
public class AzureMapsController {

    private static final Logger logger = LoggerFactory.getLogger(AzureMapsController.class);

    @Value("${azure.maps.client.id}")
    private String azureMapsClientId;

    @Value("${azure.maps.resource.id:}")
    private String azureMapsResourceId;

    /**
     * Endpoint zum Abrufen der Azure Maps Konfiguration
     * Nur authentifizierte Benutzer können diese Konfiguration abrufen
     *
     * @return ConfigResponse mit Client ID und anderen Konfigurationsdaten
     */
    @GetMapping("/config")
    @PreAuthorize("hasAuthority('SCOPE_https://yourdomain.com/api.read')") // Anpassen an Ihre API-Scopes
    public ResponseEntity<?> getConfig() {
        try {
            logger.debug("Providing Azure Maps configuration for authenticated user");

            if (azureMapsClientId == null || azureMapsClientId.trim().isEmpty()) {
                logger.error("Azure Maps Client ID is null or empty - check application.properties");
                return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                        .body(new ErrorResponse("Azure Maps Client ID not configured"));
            }

            ConfigResponse response = new ConfigResponse(
                    azureMapsClientId.trim(),
                    azureMapsResourceId != null ? azureMapsResourceId.trim() : null
            );

            logger.debug("Successfully providing Azure Maps configuration");
            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("Error providing Azure Maps configuration: {}", e.getMessage(), e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("Internal server error: " + e.getMessage()));
        }
    }

    /**
     * Health Check Endpoint für Azure Maps Integration
     * Öffentlich zugänglich für Monitoring
     *
     * @return Status der Azure Maps Konfiguration
     */
    @GetMapping("/health")
    public ResponseEntity<?> healthCheck() {
        try {
            boolean isConfigured = azureMapsClientId != null && !azureMapsClientId.trim().isEmpty();

            if (isConfigured) {
                return ResponseEntity.ok(new HealthResponse("Azure Maps Entra ID configuration is valid", true));
            } else {
                return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
                        .body(new HealthResponse("Azure Maps Client ID is not configured", false));
            }

        } catch (Exception e) {
            logger.error("Health check failed", e);
            return ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE)
                    .body(new HealthResponse("Azure Maps service is unavailable", false));
        }
    }

    /**
     * Endpoint für rollenbasierte Zugriffskontrolle
     * Prüft ob der Benutzer Azure Maps verwenden darf
     */
    @GetMapping("/permissions")
    @PreAuthorize("hasAuthority('SCOPE_https://yourdomain.com/api.read')")
    public ResponseEntity<?> checkPermissions() {
        try {
            // Hier können Sie zusätzliche Berechtigungsprüfungen implementieren
            // z.B. basierend auf Benutzerrolle, Gruppe, etc.

            PermissionResponse response = new PermissionResponse(
                    true, // canUseAzureMaps
                    true, // canCreateMarkers
                    true  // canModifyMarkers
            );

            return ResponseEntity.ok(response);

        } catch (Exception e) {
            logger.error("Error checking permissions: {}", e.getMessage(), e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
                    .body(new ErrorResponse("Error checking permissions: " + e.getMessage()));
        }
    }

    /**
     * Response-Klasse für Konfiguration
     */
    public static class ConfigResponse {
        private final String clientId;
        private final String resourceId;
        private final long timestamp;

        public ConfigResponse(String clientId, String resourceId) {
            this.clientId = clientId;
            this.resourceId = resourceId;
            this.timestamp = Instant.now().toEpochMilli();
        }

        public String getClientId() {
            return clientId;
        }

        public String getResourceId() {
            return resourceId;
        }

        public long getTimestamp() {
            return timestamp;
        }
    }

    /**
     * Response-Klasse für Berechtigungen
     */
    public static class PermissionResponse {
        private final boolean canUseAzureMaps;
        private final boolean canCreateMarkers;
        private final boolean canModifyMarkers;
        private final long timestamp;

        public PermissionResponse(boolean canUseAzureMaps, boolean canCreateMarkers, boolean canModifyMarkers) {
            this.canUseAzureMaps = canUseAzureMaps;
            this.canCreateMarkers = canCreateMarkers;
            this.canModifyMarkers = canModifyMarkers;
            this.timestamp = Instant.now().toEpochMilli();
        }

        public boolean isCanUseAzureMaps() {
            return canUseAzureMaps;
        }

        public boolean isCanCreateMarkers() {
            return canCreateMarkers;
        }

        public boolean isCanModifyMarkers() {
            return canModifyMarkers;
        }

        public long getTimestamp() {
            return timestamp;
        }
    }

    /**
     * Response-Klasse für Fehler-Antworten
     */
    public static class ErrorResponse {
        private final String error;
        private final long timestamp;

        public ErrorResponse(String error) {
            this.error = error;
            this.timestamp = Instant.now().toEpochMilli();
        }

        public String getError() {
            return error;
        }

        public long getTimestamp() {
            return timestamp;
        }
    }

    /**
     * Response-Klasse für Health Check
     */
    public static class HealthResponse {
        private final String message;
        private final boolean healthy;
        private final long timestamp;

        public HealthResponse(String message, boolean healthy) {
            this.message = message;
            this.healthy = healthy;
            this.timestamp = Instant.now().toEpochMilli();
        }

        public String getMessage() {
            return message;
        }

        public boolean isHealthy() {
            return healthy;
        }

        public long getTimestamp() {
            return timestamp;
        }
    }
}