package com.saas.admin.service;

import com.saas.admin.dto.request.CreateTenantRequest;
import com.saas.admin.dto.response.TenantResponse;
import com.saas.admin.entity.Tenant;
import com.saas.admin.repository.TenantRepository;
import com.saas.shared.audit.Auditable;
import com.saas.shared.dto.common.PageResponse;
import com.saas.shared.dto.mapper.TenantMapper;
import com.saas.shared.exception.BusinessException;
import com.saas.shared.exception.ErrorCode;
import com.saas.shared.exception.ResourceNotFoundException;
import com.saas.shared.util.SlugUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.UUID;

import com.saas.subscription.service.SubscriptionService;
import com.saas.admin.entity.TenantAIConfig;
import com.saas.admin.repository.TenantAIConfigRepository;
import com.saas.shared.enums.AIProvider;

@Service
@Slf4j
@RequiredArgsConstructor
public class TenantService {

    private final TenantRepository tenantRepository;
    private final TenantMapper tenantMapper;
    private final TenantSchemaService tenantSchemaService;
    private final SubscriptionService subscriptionService;
    private final com.saas.subscription.service.StripeService stripeService;
    private final TenantAIConfigRepository tenantAIConfigRepository;

    @Transactional
    @Auditable(action = "CREATE_TENANT", entityType = "TENANT")
    public TenantResponse createTenant(CreateTenantRequest request) {
        log.info("Creating tenant: {}", request.getTenantName());

        String slug = SlugUtils.toSlug(request.getTenantName());
        String schemaName = "tenant_" + slug;

        if (tenantRepository.existsBySchemaName(schemaName)) {
            throw new BusinessException(ErrorCode.TENANT_ALREADY_EXISTS,
                    "Tenant with name " + request.getTenantName() + " already exists");
        }

        Tenant tenant = tenantMapper.toEntity(request);
        tenant.setTenantId(UUID.randomUUID().toString());
        tenant.setSchemaName(schemaName);
        tenant.setStatus(request.getStatus() != null ? request.getStatus() : "ACTIVE");

        Tenant savedTenant = tenantRepository.save(tenant);

        // Create Stripe Customer
        try {
            String stripeCustomerId = stripeService.createCustomer(
                    savedTenant.getTenantId(),
                    request.getEmail(),
                    request.getTenantName());

            // Assign default plan and link Stripe Customer
            subscriptionService.assignDefaultPlan(savedTenant.getTenantId(), stripeCustomerId);

        } catch (Exception e) {
            log.error("Failed to create Stripe customer for tenant {}", savedTenant.getTenantId(), e);
            // We don't fail tenant creation, but we should probably alert or retry
        }

        log.info("Tenant created successfully with ID: {}", savedTenant.getTenantId());
        return tenantMapper.toResponse(savedTenant);
    }

    @Transactional(readOnly = true)
    public TenantResponse getTenantById(String tenantId) {
        log.debug("Fetching tenant with ID: {}", tenantId);
        return tenantRepository.findByTenantId(tenantId)
                .map(tenantMapper::toResponse)
                .orElseThrow(() -> new ResourceNotFoundException("Tenant", tenantId));
    }

    @Transactional(readOnly = true)
    public List<TenantResponse> getAllTenants() {
        log.debug("Fetching all tenants");
        return tenantMapper.toResponseList(tenantRepository.findAll());
    }

    @Transactional(readOnly = true)
    public PageResponse<TenantResponse> getTenants(int page, int size) {
        log.debug("Fetching tenants - page: {}, size: {}", page, size);
        Pageable pageable = PageRequest.of(page, size);
        Page<Tenant> tenantPage = tenantRepository.findAll(pageable);

        return PageResponse.<TenantResponse>builder()
                .content(tenantMapper.toResponseList(tenantPage.getContent()))
                .page(page)
                .size(size)
                .totalElements(tenantPage.getTotalElements())
                .totalPages(tenantPage.getTotalPages())
                .hasNext(tenantPage.hasNext())
                .hasPrevious(tenantPage.hasPrevious())
                .build();
    }

    @Transactional
    @Auditable(action = "UPDATE_TENANT", entityType = "TENANT")
    public TenantResponse updateTenant(String tenantId, String status) {
        log.info("Updating tenant with ID: {}", tenantId);

        Tenant tenant = tenantRepository.findByTenantId(tenantId)
                .orElseThrow(() -> new ResourceNotFoundException("Tenant", tenantId));

        if (status != null) {
            tenant.setStatus(status);
        }

        Tenant updated = tenantRepository.save(tenant);
        log.info("Tenant updated successfully with ID: {}", tenantId);

        return tenantMapper.toResponse(updated);
    }

    @Transactional
    @Auditable(action = "DELETE_TENANT", entityType = "TENANT")
    public void deleteTenant(String tenantId) {
        log.info("Deleting tenant with ID: {}", tenantId);

        Tenant tenant = tenantRepository.findByTenantId(tenantId)
                .orElseThrow(() -> new ResourceNotFoundException("Tenant", tenantId));

        tenantRepository.delete(tenant);
        log.info("Tenant deleted successfully with ID: {}", tenantId);
    }

    @Transactional
    @Auditable(action = "ASSIGN_AI", entityType = "TENANT")
    public void assignAiAssistant(String tenantId, String provider, String assistantId, String phoneNumberId) {
        log.info("Assigning AI Assistant to tenant {}: provider={}, assistantId={}", tenantId, provider, assistantId);

        Tenant tenant = tenantRepository.findByTenantId(tenantId)
                .orElseThrow(() -> new ResourceNotFoundException("Tenant", tenantId));

        TenantAIConfig config = tenantAIConfigRepository.findByTenantId(tenantId)
                .orElseGet(() -> TenantAIConfig.builder()
                        .tenantId(tenantId)
                        .enabled(true)
                        .build());

        AIProvider aiProvider = AIProvider.valueOf(provider.toUpperCase());
        config.setPrimaryProvider(aiProvider);

        if (aiProvider == AIProvider.VAPI) {
            config.setVapiAssistantId(assistantId);
            if (phoneNumberId != null)
                config.setVapiPhoneNumberId(phoneNumberId);
        } else if (aiProvider == AIProvider.RETELL) {
            config.setRetellAgentId(assistantId);
            if (phoneNumberId != null)
                config.setRetellPhoneNumberId(phoneNumberId);
        }

        tenantAIConfigRepository.save(config);
        log.info("AI Configuration updated for tenant {}", tenantId);
    }
}
