package com.flightticket.metrics;

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

import java.math.BigDecimal;
import java.util.concurrent.TimeUnit;

/**
 * Service for tracking booking modification metrics.
 * Provides comprehensive monitoring for modification operations including:
 * - Success/failure rates by modification type
 * - Cost tracking (average, total)
 * - Wallet transaction volumes
 * - API error rates
 * - Processing time percentiles
 * - Rollback frequency
 * 
 * Requirements: 8.1, 8.2, 8.4
 */
@Slf4j
@Service
public class ModificationMetricsService {

    private final MeterRegistry meterRegistry;
    
    // Counters for modification operations by type
    private final Counter modificationAttemptCounter;
    private final Counter modificationSuccessCounter;
    private final Counter modificationFailureCounter;
    private final Counter modificationRollbackCounter;
    
    // Timers for processing duration
    private final Timer modificationProcessingTimer;
    
    public ModificationMetricsService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // Initialize counters
        this.modificationAttemptCounter = Counter.builder("business.modification.attempt")
                .description("Total number of modification attempts")
                .register(meterRegistry);
        
        this.modificationSuccessCounter = Counter.builder("business.modification.success")
                .description("Total number of successful modifications")
                .register(meterRegistry);
        
        this.modificationFailureCounter = Counter.builder("business.modification.failure")
                .description("Total number of failed modifications")
                .register(meterRegistry);
        
        this.modificationRollbackCounter = Counter.builder("business.modification.rollback")
                .description("Total number of modification rollbacks")
                .register(meterRegistry);
        
        // Initialize timer
        this.modificationProcessingTimer = Timer.builder("business.modification.processing.duration")
                .description("Duration of modification processing operations")
                .publishPercentiles(0.5, 0.95, 0.99) // p50, p95, p99
                .register(meterRegistry);
    }

    /**
     * Record a modification attempt.
     * 
     * @param modificationType Type of modification (PASSENGER_DETAILS, FLIGHT_DATE, etc.)
     * @param agencyId Agency performing the modification
     */
    public void recordModificationAttempt(String modificationType, String agencyId) {
        modificationAttemptCounter.increment();
        meterRegistry.counter("business.modification.attempt.by.type", 
                "type", modificationType, 
                "agencyId", agencyId).increment();
        log.debug("Recorded modification attempt - type: {}, agency: {}", modificationType, agencyId);
    }

    /**
     * Record a successful modification.
     * 
     * @param modificationType Type of modification
     * @param agencyId Agency performing the modification
     * @param cost Total modification cost
     */
    public void recordModificationSuccess(String modificationType, String agencyId, BigDecimal cost) {
        modificationSuccessCounter.increment();
        meterRegistry.counter("business.modification.success.by.type", 
                "type", modificationType, 
                "agencyId", agencyId).increment();
        
        // Record cost
        meterRegistry.summary("business.modification.cost", 
                "type", modificationType, 
                "agencyId", agencyId).record(cost.doubleValue());
        
        log.debug("Recorded modification success - type: {}, agency: {}, cost: {}", 
                modificationType, agencyId, cost);
    }

    /**
     * Record a failed modification.
     * 
     * @param modificationType Type of modification
     * @param agencyId Agency performing the modification
     * @param failureReason Reason for failure
     */
    public void recordModificationFailure(String modificationType, String agencyId, String failureReason) {
        modificationFailureCounter.increment();
        meterRegistry.counter("business.modification.failure.by.type", 
                "type", modificationType, 
                "agencyId", agencyId, 
                "reason", failureReason).increment();
        log.debug("Recorded modification failure - type: {}, agency: {}, reason: {}", 
                modificationType, agencyId, failureReason);
    }

    /**
     * Record a modification rollback.
     * 
     * @param modificationType Type of modification
     * @param agencyId Agency performing the modification
     * @param rollbackReason Reason for rollback
     */
    public void recordModificationRollback(String modificationType, String agencyId, String rollbackReason) {
        modificationRollbackCounter.increment();
        meterRegistry.counter("business.modification.rollback.by.type", 
                "type", modificationType, 
                "agencyId", agencyId, 
                "reason", rollbackReason).increment();
        log.debug("Recorded modification rollback - type: {}, agency: {}, reason: {}", 
                modificationType, agencyId, rollbackReason);
    }

    /**
     * Record modification processing duration.
     * 
     * @param modificationType Type of modification
     * @param durationMillis Processing duration in milliseconds
     */
    public void recordModificationProcessingDuration(String modificationType, long durationMillis) {
        modificationProcessingTimer.record(durationMillis, TimeUnit.MILLISECONDS);
        meterRegistry.timer("business.modification.processing.duration.by.type", 
                "type", modificationType)
                .record(durationMillis, TimeUnit.MILLISECONDS);
        log.debug("Recorded modification processing duration - type: {}, duration: {}ms", 
                modificationType, durationMillis);
    }

    /**
     * Record wallet transaction for modification.
     * 
     * @param transactionType Type of transaction (DEBIT or CREDIT)
     * @param amount Transaction amount
     * @param agencyId Agency ID
     */
    public void recordModificationWalletTransaction(String transactionType, BigDecimal amount, String agencyId) {
        meterRegistry.counter("business.modification.wallet.transaction", 
                "type", transactionType, 
                "agencyId", agencyId).increment();
        
        meterRegistry.summary("business.modification.wallet.transaction.amount", 
                "type", transactionType, 
                "agencyId", agencyId).record(amount.doubleValue());
        
        log.debug("Recorded modification wallet transaction - type: {}, agency: {}, amount: {}", 
                transactionType, agencyId, amount);
    }

    /**
     * Record Amadeus API error during modification.
     * 
     * @param errorType Type of error
     * @param modificationType Type of modification being attempted
     */
    public void recordModificationApiError(String errorType, String modificationType) {
        meterRegistry.counter("business.modification.api.error", 
                "errorType", errorType, 
                "modificationType", modificationType).increment();
        log.debug("Recorded modification API error - type: {}, modification: {}", 
                errorType, modificationType);
    }

    /**
     * Calculate and record modification success rate.
     * This is a derived metric calculated from success and attempt counters.
     * 
     * @param modificationType Type of modification
     * @return Success rate as a percentage (0-100)
     */
    public double getModificationSuccessRate(String modificationType) {
        double attempts = meterRegistry.counter("business.modification.attempt.by.type", 
                "type", modificationType).count();
        double successes = meterRegistry.counter("business.modification.success.by.type", 
                "type", modificationType).count();
        
        if (attempts == 0) {
            return 100.0; // No attempts means 100% success rate
        }
        
        double successRate = (successes / attempts) * 100.0;
        
        // Record as gauge for monitoring
        meterRegistry.gauge("business.modification.success.rate", 
                java.util.Collections.singletonList(io.micrometer.core.instrument.Tag.of("type", modificationType)), 
                successRate);
        
        return successRate;
    }

    /**
     * Calculate and record API error rate.
     * 
     * @return API error rate as a percentage (0-100)
     */
    public double getApiErrorRate() {
        double totalAttempts = modificationAttemptCounter.count();
        double totalApiErrors = meterRegistry.counter("business.modification.api.error").count();
        
        if (totalAttempts == 0) {
            return 0.0;
        }
        
        double errorRate = (totalApiErrors / totalAttempts) * 100.0;
        
        // Record as gauge for monitoring
        meterRegistry.gauge("business.modification.api.error.rate", errorRate);
        
        return errorRate;
    }

    /**
     * Calculate and record rollback rate.
     * 
     * @return Rollback rate as a percentage (0-100)
     */
    public double getRollbackRate() {
        double totalAttempts = modificationAttemptCounter.count();
        double totalRollbacks = modificationRollbackCounter.count();
        
        if (totalAttempts == 0) {
            return 0.0;
        }
        
        double rollbackRate = (totalRollbacks / totalAttempts) * 100.0;
        
        // Record as gauge for monitoring
        meterRegistry.gauge("business.modification.rollback.rate", rollbackRate);
        
        return rollbackRate;
    }

    /**
     * Get average modification cost.
     * 
     * @param modificationType Type of modification
     * @return Average cost
     */
    public double getAverageModificationCost(String modificationType) {
        return meterRegistry.summary("business.modification.cost", 
                "type", modificationType).mean();
    }
}
