package com.saas.subscription.service.impl;

import com.saas.shared.exception.BusinessException;
import com.saas.shared.exception.ErrorCode;
import com.saas.subscription.dto.request.CreateSubscriptionPlanRequest;
import com.saas.subscription.dto.response.SubscriptionPlanResponse;
import com.saas.subscription.entity.SubscriptionPlan;
import com.saas.subscription.repository.SubscriptionPlanRepository;
import com.saas.subscription.service.SubscriptionPlanService;
import com.saas.shared.dto.mapper.SubscriptionPlanMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

/**
 * Implementation of SubscriptionPlanService.
 * 
 * Manages subscription plan CRUD operations with Stripe integration.
 * All operations logged for audit trail.
 */
@Service
@Slf4j
@RequiredArgsConstructor
@Transactional
public class SubscriptionPlanServiceImpl implements SubscriptionPlanService {

    private final SubscriptionPlanRepository planRepository;
    private final SubscriptionPlanMapper planMapper;
    // TODO: Inject StripeService for Stripe Product/Price creation
    // private final StripeService stripeService;

    @Override
    public SubscriptionPlanResponse createPlan(CreateSubscriptionPlanRequest request) {
        log.debug("Creating subscription plan: {}", request.getName());

        // Validation: Plan name uniqueness
        if (planRepository.findByName(request.getName()).isPresent()) {
            log.warn("Plan name already exists: {}", request.getName());
            throw new BusinessException(
                ErrorCode.SUBSCRIPTION_PLAN_ALREADY_EXISTS,
                "Subscription plan '" + request.getName() + "' already exists"
            );
        }

        // Validation: Annual price should be less than 12 * monthly
        if (request.getAnnualPrice() != null && 
            request.getAnnualPrice().compareTo(request.getMonthlyPrice().multiply(java.math.BigDecimal.valueOf(12))) > 0) {
            log.warn("Annual price exceeds 12x monthly price for plan: {}", request.getName());
            throw new BusinessException(
                ErrorCode.INVALID_INPUT,
                "Annual price cannot exceed 12 times the monthly price"
            );
        }

        // Build entity
        SubscriptionPlan plan = SubscriptionPlan.builder()
            .name(request.getName())
            .description(request.getDescription())
            .pricePerMonth(request.getMonthlyPrice())
            .pricePerYear(request.getAnnualPrice() != null ? request.getAnnualPrice() : request.getMonthlyPrice().multiply(java.math.BigDecimal.valueOf(12)))
            .maxConcurrentCalls(request.getMaxConcurrentCalls())
            .maxAiMinutes(request.getMaxAiMinutes())
            .maxActiveAiAgents(request.getMaxAiAgents())
            .maxUsers(request.getMaxUsers())
            .maxPhoneNumbers(request.getMaxPhoneNumbers())
            .maxStorageGb(request.getStorageQuotaGb())
            .active(true)
            .build();

        // TODO: Create Stripe Product and Price
        // StripeProductResponse stripeProduct = stripeService.createProduct(plan);
        // plan.setStripeProductId(stripeProduct.getId());
        // plan.setStripePriceId(stripeProduct.getDefaultPriceId());

        SubscriptionPlan savedPlan = planRepository.save(plan);
        log.info("Subscription plan created successfully: {} (ID: {})", plan.getName(), savedPlan.getId());

        return planMapper.toResponse(savedPlan);
    }

    @Override
    @Transactional(readOnly = true)
    public SubscriptionPlanResponse getPlan(Long planId) {
        log.debug("Fetching subscription plan: {}", planId);

        SubscriptionPlan plan = planRepository.findById(planId)
            .orElseThrow(() -> {
                log.warn("Subscription plan not found: {}", planId);
                return new BusinessException(
                    ErrorCode.SUBSCRIPTION_PLAN_NOT_FOUND,
                    "Subscription plan with ID " + planId + " does not exist"
                );
            });

        return planMapper.toResponse(plan);
    }

    @Override
    @Transactional(readOnly = true)
    public List<SubscriptionPlanResponse> getAllActivePlans() {
        log.debug("Fetching all active subscription plans");

        return planRepository.findAllActive()
            .stream()
            .map(planMapper::toResponse)
            .collect(Collectors.toList());
    }

    @Override
    public SubscriptionPlanResponse updatePlan(Long planId, CreateSubscriptionPlanRequest request) {
        log.debug("Updating subscription plan: {}", planId);

        SubscriptionPlan plan = planRepository.findById(planId)
            .orElseThrow(() -> {
                log.warn("Subscription plan not found for update: {}", planId);
                return new BusinessException(
                    ErrorCode.SUBSCRIPTION_PLAN_NOT_FOUND,
                    "Subscription plan with ID " + planId + " does not exist"
                );
            });

        // Check if new name is already taken by another plan
        if (!plan.getName().equals(request.getName()) && 
            planRepository.existsNameExcludingId(request.getName(), planId)) {
            log.warn("New plan name already exists: {}", request.getName());
            throw new BusinessException(
                ErrorCode.SUBSCRIPTION_PLAN_ALREADY_EXISTS,
                "Plan name '" + request.getName() + "' is already in use"
            );
        }

        // Update fields
        plan.setDescription(request.getDescription());
        plan.setPricePerMonth(request.getMonthlyPrice());
        plan.setPricePerYear(request.getAnnualPrice() != null ? request.getAnnualPrice() : request.getMonthlyPrice().multiply(java.math.BigDecimal.valueOf(12)));
        plan.setMaxConcurrentCalls(request.getMaxConcurrentCalls());
        plan.setMaxAiMinutes(request.getMaxAiMinutes());
        plan.setMaxActiveAiAgents(request.getMaxAiAgents());
        plan.setMaxUsers(request.getMaxUsers());
        plan.setMaxPhoneNumbers(request.getMaxPhoneNumbers());
        plan.setMaxStorageGb(request.getStorageQuotaGb());

        SubscriptionPlan updatedPlan = planRepository.save(plan);
        log.info("Subscription plan updated: {} (ID: {})", plan.getName(), planId);

        return planMapper.toResponse(updatedPlan);
    }

    @Override
    public void deletePlan(Long planId) {
        log.debug("Deactivating subscription plan: {}", planId);

        if (!planRepository.existsById(planId)) {
            log.warn("Subscription plan not found for deletion: {}", planId);
            throw new BusinessException(
                ErrorCode.SUBSCRIPTION_PLAN_NOT_FOUND,
                "Subscription plan with ID " + planId + " does not exist"
            );
        }

        planRepository.deactivate(planId);
        log.info("Subscription plan deactivated: {}", planId);
    }

    @Override
    @Transactional(readOnly = true)
    public boolean isPlanAvailable(Long planId) {
        return planRepository.existsAndActive(planId);
    }
}
