package com.gnx.telemedicine.metrics;

import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import io.micrometer.core.instrument.Gauge;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * Custom metrics for telemedicine application.
 * Provides business-specific metrics for monitoring and observability.
 */
@Component
@RequiredArgsConstructor
@Slf4j
public class TelemedicineMetrics {
    
    private final MeterRegistry meterRegistry;
    
    // Counters
    private Counter loginAttemptsCounter;
    private Counter loginSuccessCounter;
    private Counter loginFailureCounter;
    private Counter appointmentCreatedCounter;
    private Counter appointmentCancelledCounter;
    private Counter appointmentCompletedCounter;
    private Counter prescriptionCreatedCounter;
    private Counter messageSentCounter;
    private Counter apiRequestCounter;
    private Counter apiErrorCounter;
    private Counter passwordResetRequestCounter;
    private Counter passwordResetSuccessCounter;
    private Counter twoFactorAuthEnabledCounter;
    private Counter twoFactorAuthVerifiedCounter;
    private Counter phiAccessCounter;
    private Counter breachNotificationCounter;
    
    // Timers
    private Timer apiResponseTimeTimer;
    private Timer databaseQueryTimer;
    private Timer authenticationTimer;
    private Timer appointmentCreationTimer;
    private Timer prescriptionCreationTimer;
    private Timer messageProcessingTimer;
    
    // Gauges
    private final AtomicInteger activeUsers = new AtomicInteger(0);
    private final AtomicInteger activeAppointments = new AtomicInteger(0);
    private final AtomicInteger activePrescriptions = new AtomicInteger(0);
    private final AtomicLong totalUsers = new AtomicLong(0);
    private final AtomicLong totalAppointments = new AtomicLong(0);
    private final AtomicLong totalPrescriptions = new AtomicLong(0);
    
    /**
     * Initialize metrics after construction.
     */
    public void initialize() {
        // Initialize counters
        loginAttemptsCounter = Counter.builder("telemedicine.auth.login.attempts")
                .description("Total number of login attempts")
                .tag("type", "attempt")
                .register(meterRegistry);
        
        loginSuccessCounter = Counter.builder("telemedicine.auth.login.success")
                .description("Total number of successful logins")
                .tag("type", "success")
                .register(meterRegistry);
        
        loginFailureCounter = Counter.builder("telemedicine.auth.login.failure")
                .description("Total number of failed logins")
                .tag("type", "failure")
                .register(meterRegistry);
        
        appointmentCreatedCounter = Counter.builder("telemedicine.appointments.created")
                .description("Total number of appointments created")
                .register(meterRegistry);
        
        appointmentCancelledCounter = Counter.builder("telemedicine.appointments.cancelled")
                .description("Total number of appointments cancelled")
                .register(meterRegistry);
        
        appointmentCompletedCounter = Counter.builder("telemedicine.appointments.completed")
                .description("Total number of appointments completed")
                .register(meterRegistry);
        
        prescriptionCreatedCounter = Counter.builder("telemedicine.prescriptions.created")
                .description("Total number of prescriptions created")
                .register(meterRegistry);
        
        messageSentCounter = Counter.builder("telemedicine.messages.sent")
                .description("Total number of messages sent")
                .register(meterRegistry);
        
        apiRequestCounter = Counter.builder("telemedicine.api.requests")
                .description("Total number of API requests")
                .register(meterRegistry);
        
        apiErrorCounter = Counter.builder("telemedicine.api.errors")
                .description("Total number of API errors")
                .register(meterRegistry);
        
        passwordResetRequestCounter = Counter.builder("telemedicine.auth.password.reset.requests")
                .description("Total number of password reset requests")
                .register(meterRegistry);
        
        passwordResetSuccessCounter = Counter.builder("telemedicine.auth.password.reset.success")
                .description("Total number of successful password resets")
                .register(meterRegistry);
        
        twoFactorAuthEnabledCounter = Counter.builder("telemedicine.auth.2fa.enabled")
                .description("Total number of 2FA enabled")
                .register(meterRegistry);
        
        twoFactorAuthVerifiedCounter = Counter.builder("telemedicine.auth.2fa.verified")
                .description("Total number of 2FA verifications")
                .register(meterRegistry);
        
        phiAccessCounter = Counter.builder("telemedicine.phi.access")
                .description("Total number of PHI access events")
                .register(meterRegistry);
        
        breachNotificationCounter = Counter.builder("telemedicine.breach.notifications")
                .description("Total number of breach notifications")
                .register(meterRegistry);
        
        // Initialize timers
        apiResponseTimeTimer = Timer.builder("telemedicine.api.response.time")
                .description("API response time")
                .register(meterRegistry);
        
        databaseQueryTimer = Timer.builder("telemedicine.database.query.time")
                .description("Database query execution time")
                .register(meterRegistry);
        
        authenticationTimer = Timer.builder("telemedicine.auth.authentication.time")
                .description("Authentication processing time")
                .register(meterRegistry);
        
        appointmentCreationTimer = Timer.builder("telemedicine.appointments.creation.time")
                .description("Appointment creation time")
                .register(meterRegistry);
        
        prescriptionCreationTimer = Timer.builder("telemedicine.prescriptions.creation.time")
                .description("Prescription creation time")
                .register(meterRegistry);
        
        messageProcessingTimer = Timer.builder("telemedicine.messages.processing.time")
                .description("Message processing time")
                .register(meterRegistry);
        
        // Initialize gauges
        Gauge.builder("telemedicine.users.active", activeUsers, AtomicInteger::get)
                .description("Number of active users")
                .register(meterRegistry);
        
        Gauge.builder("telemedicine.appointments.active", activeAppointments, AtomicInteger::get)
                .description("Number of active appointments")
                .register(meterRegistry);
        
        Gauge.builder("telemedicine.prescriptions.active", activePrescriptions, AtomicInteger::get)
                .description("Number of active prescriptions")
                .register(meterRegistry);
        
        Gauge.builder("telemedicine.users.total", totalUsers, AtomicLong::get)
                .description("Total number of users")
                .register(meterRegistry);
        
        Gauge.builder("telemedicine.appointments.total", totalAppointments, AtomicLong::get)
                .description("Total number of appointments")
                .register(meterRegistry);
        
        Gauge.builder("telemedicine.prescriptions.total", totalPrescriptions, AtomicLong::get)
                .description("Total number of prescriptions")
                .register(meterRegistry);
        
        log.info("Telemedicine metrics initialized");
    }
    
    // Authentication metrics
    public void recordLoginAttempt() {
        loginAttemptsCounter.increment();
    }
    
    public void recordLoginSuccess() {
        loginSuccessCounter.increment();
    }
    
    public void recordLoginFailure() {
        loginFailureCounter.increment();
    }
    
    public Timer.Sample startAuthenticationTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void recordAuthenticationTime(Timer.Sample sample) {
        sample.stop(authenticationTimer);
    }
    
    // Appointment metrics
    public void recordAppointmentCreated() {
        appointmentCreatedCounter.increment();
        activeAppointments.incrementAndGet();
        totalAppointments.incrementAndGet();
    }
    
    public void recordAppointmentCancelled() {
        appointmentCancelledCounter.increment();
        activeAppointments.decrementAndGet();
    }
    
    public void recordAppointmentCompleted() {
        appointmentCompletedCounter.increment();
        activeAppointments.decrementAndGet();
    }
    
    public Timer.Sample startAppointmentCreationTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void recordAppointmentCreationTime(Timer.Sample sample) {
        sample.stop(appointmentCreationTimer);
    }
    
    // Prescription metrics
    public void recordPrescriptionCreated() {
        prescriptionCreatedCounter.increment();
        activePrescriptions.incrementAndGet();
        totalPrescriptions.incrementAndGet();
    }
    
    public Timer.Sample startPrescriptionCreationTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void recordPrescriptionCreationTime(Timer.Sample sample) {
        sample.stop(prescriptionCreationTimer);
    }
    
    // Message metrics
    public void recordMessageSent() {
        messageSentCounter.increment();
    }
    
    public Timer.Sample startMessageProcessingTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void recordMessageProcessingTime(Timer.Sample sample) {
        sample.stop(messageProcessingTimer);
    }
    
    // API metrics
    public void recordApiRequest(String endpoint, String method) {
        meterRegistry.counter("telemedicine.api.requests", 
            io.micrometer.core.instrument.Tags.of("endpoint", endpoint, "method", method)
        ).increment();
    }
    
    public void recordApiError(String endpoint, String method, String status) {
        meterRegistry.counter("telemedicine.api.errors",
            io.micrometer.core.instrument.Tags.of("endpoint", endpoint, "method", method, "status", status)
        ).increment();
    }
    
    public Timer.Sample startApiResponseTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void recordApiResponseTime(Timer.Sample sample, String endpoint, String method) {
        sample.stop(Timer.builder("telemedicine.api.response.time")
                .description("API response time")
                .tag("endpoint", endpoint)
                .tag("method", method)
                .register(meterRegistry));
    }
    
    // Database metrics
    public Timer.Sample startDatabaseQueryTimer() {
        return Timer.start(meterRegistry);
    }
    
    public void recordDatabaseQueryTime(Timer.Sample sample, String queryType) {
        sample.stop(Timer.builder("telemedicine.database.query.time")
                .description("Database query execution time")
                .tag("query.type", queryType)
                .register(meterRegistry));
    }
    
    // Password reset metrics
    public void recordPasswordResetRequest() {
        passwordResetRequestCounter.increment();
    }
    
    public void recordPasswordResetSuccess() {
        passwordResetSuccessCounter.increment();
    }
    
    // 2FA metrics
    public void record2FAEnabled() {
        twoFactorAuthEnabledCounter.increment();
    }
    
    public void record2FAVerified() {
        twoFactorAuthVerifiedCounter.increment();
    }
    
    // PHI access metrics
    public void recordPHIAccess(String resourceType, String action) {
        meterRegistry.counter("telemedicine.phi.access",
            io.micrometer.core.instrument.Tags.of("resource", resourceType, "action", action)
        ).increment();
    }
    
    // Breach notification metrics
    public void recordBreachNotification() {
        breachNotificationCounter.increment();
    }
    
    // User metrics
    public void incrementActiveUsers() {
        activeUsers.incrementAndGet();
    }
    
    public void decrementActiveUsers() {
        activeUsers.decrementAndGet();
    }
    
    public void setTotalUsers(long count) {
        totalUsers.set(count);
    }
    
    public void setTotalAppointments(long count) {
        totalAppointments.set(count);
    }
    
    public void setTotalPrescriptions(long count) {
        totalPrescriptions.set(count);
    }
}

