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 custom business metrics.
 * Provides methods to record business operations for monitoring and analytics.
 * Validates: Requirement 13.6
 */
@Slf4j
@Service
public class BusinessMetricsService {

    private final MeterRegistry meterRegistry;
    
    // Counters for business operations
    private final Counter bookingCreatedCounter;
    private final Counter bookingFailedCounter;
    private final Counter ticketIssuedCounter;
    private final Counter ticketFailedCounter;
    private final Counter ticketVoidedCounter;
    private final Counter ticketRefundedCounter;
    private final Counter walletRechargeCounter;
    private final Counter walletDebitCounter;
    private final Counter walletCreditCounter;
    private final Counter authenticationSuccessCounter;
    private final Counter authenticationFailureCounter;
    private final Counter amadeusApiCallCounter;
    private final Counter amadeusApiErrorCounter;
    
    // Timers for operation duration
    private final Timer flightSearchTimer;
    private final Timer bookingCreationTimer;
    private final Timer ticketIssuanceTimer;
    private final Timer amadeusApiCallTimer;

    public BusinessMetricsService(MeterRegistry meterRegistry) {
        this.meterRegistry = meterRegistry;
        
        // Initialize counters
        this.bookingCreatedCounter = Counter.builder("business.booking.created")
                .description("Total number of bookings created")
                .register(meterRegistry);
        
        this.bookingFailedCounter = Counter.builder("business.booking.failed")
                .description("Total number of failed booking attempts")
                .register(meterRegistry);
        
        this.ticketIssuedCounter = Counter.builder("business.ticket.issued")
                .description("Total number of tickets issued")
                .register(meterRegistry);
        
        this.ticketFailedCounter = Counter.builder("business.ticket.failed")
                .description("Total number of failed ticket issuance attempts")
                .register(meterRegistry);
        
        this.ticketVoidedCounter = Counter.builder("business.ticket.voided")
                .description("Total number of tickets voided")
                .register(meterRegistry);
        
        this.ticketRefundedCounter = Counter.builder("business.ticket.refunded")
                .description("Total number of tickets refunded")
                .register(meterRegistry);
        
        this.walletRechargeCounter = Counter.builder("business.wallet.recharge")
                .description("Total number of wallet recharges")
                .register(meterRegistry);
        
        this.walletDebitCounter = Counter.builder("business.wallet.debit")
                .description("Total number of wallet debits")
                .register(meterRegistry);
        
        this.walletCreditCounter = Counter.builder("business.wallet.credit")
                .description("Total number of wallet credits")
                .register(meterRegistry);
        
        this.authenticationSuccessCounter = Counter.builder("business.authentication.success")
                .description("Total number of successful authentications")
                .register(meterRegistry);
        
        this.authenticationFailureCounter = Counter.builder("business.authentication.failure")
                .description("Total number of failed authentication attempts")
                .register(meterRegistry);
        
        this.amadeusApiCallCounter = Counter.builder("business.amadeus.api.call")
                .description("Total number of Amadeus API calls")
                .register(meterRegistry);
        
        this.amadeusApiErrorCounter = Counter.builder("business.amadeus.api.error")
                .description("Total number of Amadeus API errors")
                .register(meterRegistry);
        
        // Initialize timers
        this.flightSearchTimer = Timer.builder("business.flight.search.duration")
                .description("Duration of flight search operations")
                .register(meterRegistry);
        
        this.bookingCreationTimer = Timer.builder("business.booking.creation.duration")
                .description("Duration of booking creation operations")
                .register(meterRegistry);
        
        this.ticketIssuanceTimer = Timer.builder("business.ticket.issuance.duration")
                .description("Duration of ticket issuance operations")
                .register(meterRegistry);
        
        this.amadeusApiCallTimer = Timer.builder("business.amadeus.api.call.duration")
                .description("Duration of Amadeus API calls")
                .register(meterRegistry);
    }

    // Booking metrics
    public void recordBookingCreated(String agencyId) {
        bookingCreatedCounter.increment();
        meterRegistry.counter("business.booking.created.by.agency", "agencyId", agencyId).increment();
        log.debug("Recorded booking created for agency: {}", agencyId);
    }

    public void recordBookingFailed(String agencyId, String reason) {
        bookingFailedCounter.increment();
        meterRegistry.counter("business.booking.failed.by.agency", "agencyId", agencyId, "reason", reason).increment();
        log.debug("Recorded booking failed for agency: {}, reason: {}", agencyId, reason);
    }

    public void recordBookingCreationDuration(long durationMillis) {
        bookingCreationTimer.record(durationMillis, TimeUnit.MILLISECONDS);
    }

    // Ticket metrics
    public void recordTicketIssued(String agencyId, BigDecimal amount) {
        ticketIssuedCounter.increment();
        meterRegistry.counter("business.ticket.issued.by.agency", "agencyId", agencyId).increment();
        meterRegistry.summary("business.ticket.amount", "agencyId", agencyId).record(amount.doubleValue());
        log.debug("Recorded ticket issued for agency: {}, amount: {}", agencyId, amount);
    }

    public void recordTicketFailed(String agencyId, String reason) {
        ticketFailedCounter.increment();
        meterRegistry.counter("business.ticket.failed.by.agency", "agencyId", agencyId, "reason", reason).increment();
        log.debug("Recorded ticket failed for agency: {}, reason: {}", agencyId, reason);
    }

    public void recordTicketVoided(String agencyId, BigDecimal refundAmount) {
        ticketVoidedCounter.increment();
        meterRegistry.counter("business.ticket.voided.by.agency", "agencyId", agencyId).increment();
        meterRegistry.summary("business.ticket.void.amount", "agencyId", agencyId).record(refundAmount.doubleValue());
        log.debug("Recorded ticket voided for agency: {}, refund: {}", agencyId, refundAmount);
    }

    public void recordTicketRefunded(String agencyId, BigDecimal refundAmount) {
        ticketRefundedCounter.increment();
        meterRegistry.counter("business.ticket.refunded.by.agency", "agencyId", agencyId).increment();
        meterRegistry.summary("business.ticket.refund.amount", "agencyId", agencyId).record(refundAmount.doubleValue());
        log.debug("Recorded ticket refunded for agency: {}, refund: {}", agencyId, refundAmount);
    }

    public void recordTicketIssuanceDuration(long durationMillis) {
        ticketIssuanceTimer.record(durationMillis, TimeUnit.MILLISECONDS);
    }

    // Wallet metrics
    public void recordWalletRecharge(String agencyId, BigDecimal amount) {
        walletRechargeCounter.increment();
        meterRegistry.counter("business.wallet.recharge.by.agency", "agencyId", agencyId).increment();
        meterRegistry.summary("business.wallet.recharge.amount", "agencyId", agencyId).record(amount.doubleValue());
        log.debug("Recorded wallet recharge for agency: {}, amount: {}", agencyId, amount);
    }

    public void recordWalletDebit(String agencyId, BigDecimal amount) {
        walletDebitCounter.increment();
        meterRegistry.counter("business.wallet.debit.by.agency", "agencyId", agencyId).increment();
        meterRegistry.summary("business.wallet.debit.amount", "agencyId", agencyId).record(amount.doubleValue());
        log.debug("Recorded wallet debit for agency: {}, amount: {}", agencyId, amount);
    }

    public void recordWalletCredit(String agencyId, BigDecimal amount) {
        walletCreditCounter.increment();
        meterRegistry.counter("business.wallet.credit.by.agency", "agencyId", agencyId).increment();
        meterRegistry.summary("business.wallet.credit.amount", "agencyId", agencyId).record(amount.doubleValue());
        log.debug("Recorded wallet credit for agency: {}, amount: {}", agencyId, amount);
    }

    // Authentication metrics
    public void recordAuthenticationSuccess(String username) {
        authenticationSuccessCounter.increment();
        log.debug("Recorded authentication success for user: {}", username);
    }

    public void recordAuthenticationFailure(String username, String reason) {
        authenticationFailureCounter.increment();
        meterRegistry.counter("business.authentication.failure.by.reason", "reason", reason).increment();
        log.debug("Recorded authentication failure for user: {}, reason: {}", username, reason);
    }

    // Amadeus API metrics
    public void recordAmadeusApiCall(String endpoint) {
        amadeusApiCallCounter.increment();
        meterRegistry.counter("business.amadeus.api.call.by.endpoint", "endpoint", endpoint).increment();
        log.debug("Recorded Amadeus API call to endpoint: {}", endpoint);
    }

    public void recordAmadeusApiError(String endpoint, String errorType) {
        amadeusApiErrorCounter.increment();
        meterRegistry.counter("business.amadeus.api.error.by.endpoint", "endpoint", endpoint, "errorType", errorType).increment();
        log.debug("Recorded Amadeus API error for endpoint: {}, error: {}", endpoint, errorType);
    }

    public void recordAmadeusApiCallDuration(String endpoint, long durationMillis) {
        amadeusApiCallTimer.record(durationMillis, TimeUnit.MILLISECONDS);
        meterRegistry.timer("business.amadeus.api.call.duration.by.endpoint", "endpoint", endpoint)
                .record(durationMillis, TimeUnit.MILLISECONDS);
    }

    // Flight search metrics
    public void recordFlightSearch(String agencyId, String origin, String destination) {
        meterRegistry.counter("business.flight.search", "agencyId", agencyId, "origin", origin, "destination", destination).increment();
        log.debug("Recorded flight search for agency: {}, route: {}-{}", agencyId, origin, destination);
    }

    public void recordFlightSearchDuration(long durationMillis) {
        flightSearchTimer.record(durationMillis, TimeUnit.MILLISECONDS);
    }

    // Gauge for current wallet balances (to be called periodically)
    public void recordWalletBalance(String agencyId, BigDecimal balance) {
        meterRegistry.gauge("business.wallet.balance", 
                java.util.Collections.singletonList(io.micrometer.core.instrument.Tag.of("agencyId", agencyId)), 
                balance, 
                BigDecimal::doubleValue);
    }
}
