package com.social.media.infrastructure.persistence.socialaccount;

import com.social.media.application.socialaccount.dto.SocialAccountResponseDto;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * Repository adapter that implements business logic for Social Account persistence
 * This bridges the domain layer with the JPA infrastructure
 */
@Repository
@Transactional
public class SocialAccountRepositoryAdapter {

    private final SocialAccountJpaRepository jpaRepository;
    private final SocialAccountMapper mapper;

    public SocialAccountRepositoryAdapter(SocialAccountJpaRepository jpaRepository, 
                                        SocialAccountMapper mapper) {
        this.jpaRepository = jpaRepository;
        this.mapper = mapper;
    }

    /**
     * Save social account
     */
    public SocialAccountResponseDto save(SocialAccountJpaEntity entity) {
        SocialAccountJpaEntity savedEntity = jpaRepository.save(entity);
        return mapper.toResponseDto(savedEntity);
    }

    /**
     * Find social account by ID
     */
    public Optional<SocialAccountResponseDto> findById(Long id) {
        return jpaRepository.findById(id)
                .map(mapper::toResponseDto);
    }

    /**
     * Find social account by account code
     */
    public Optional<SocialAccountResponseDto> findByAccountCode(String accountCode) {
        return jpaRepository.findByAccountCode(accountCode)
                .map(mapper::toResponseDto);
    }

    /**
     * Find all social accounts by company ID
     */
    public List<SocialAccountResponseDto> findByCompanyId(Long companyId) {
        return jpaRepository.findByCompanyIdAndDeletedFalse(companyId)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Find social accounts by company ID with pagination
     */
    public Page<SocialAccountResponseDto> findByCompanyId(Long companyId, Pageable pageable) {
        return jpaRepository.findByCompanyIdAndDeletedFalse(companyId, pageable)
                .map(mapper::toResponseDto);
    }

    /**
     * Find social accounts by responsible user ID
     */
    public List<SocialAccountResponseDto> findByResponsibleUserId(Long responsibleUserId) {
        return jpaRepository.findByResponsibleUserIdAndDeletedFalse(responsibleUserId)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Find social accounts by social network ID
     */
    public List<SocialAccountResponseDto> findBySocialNetworkId(Long socialNetworkId) {
        return jpaRepository.findBySocialNetworkIdAndDeletedFalse(socialNetworkId)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Find social account by username and social network ID
     */
    public Optional<SocialAccountResponseDto> findByUsernameAndSocialNetworkId(
            String username, Long socialNetworkId) {
        return jpaRepository.findByUsernameAndSocialNetworkIdAndDeletedFalse(username, socialNetworkId)
                .map(mapper::toResponseDto);
    }

    /**
     * Find social accounts by connection status
     */
    public List<SocialAccountResponseDto> findByConnectionStatus(
            SocialAccountJpaEntity.ConnectionStatusEnum status) {
        return jpaRepository.findByConnectionStatusAndDeletedFalse(status)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Find active social accounts by company ID
     */
    public List<SocialAccountResponseDto> findActiveAccountsByCompanyId(Long companyId) {
        return jpaRepository.findByCompanyIdAndActiveTrueAndDeletedFalse(companyId)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Find active social accounts by responsible user ID
     */
    public List<SocialAccountResponseDto> findActiveAccountsByResponsibleUserId(Long responsibleUserId) {
        return jpaRepository.findByResponsibleUserIdAndActiveTrueAndDeletedFalse(responsibleUserId)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Check if username exists for social network
     */
    public boolean existsByUsernameAndSocialNetworkId(String username, Long socialNetworkId) {
        return jpaRepository.existsByUsernameAndSocialNetworkIdAndDeletedFalse(username, socialNetworkId);
    }

    /**
     * Count social accounts by company ID
     */
    public long countByCompanyId(Long companyId) {
        return jpaRepository.countByCompanyIdAndDeletedFalse(companyId);
    }

    /**
     * Count active social accounts by company ID
     */
    public long countActiveByCompanyId(Long companyId) {
        return jpaRepository.countByCompanyIdAndActiveTrueAndDeletedFalse(companyId);
    }

    /**
     * Count social accounts by responsible user ID
     */
    public long countByResponsibleUserId(Long responsibleUserId) {
        return jpaRepository.countByResponsibleUserIdAndDeletedFalse(responsibleUserId);
    }

    /**
     * Find accounts that need sync
     */
    public List<SocialAccountResponseDto> findAccountsNeedingSync(LocalDateTime syncThreshold) {
        return jpaRepository.findAccountsNeedingSync(syncThreshold)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Find accounts with expired tokens
     */
    public List<SocialAccountResponseDto> findAccountsWithExpiredTokens() {
        return jpaRepository.findAccountsWithExpiredTokens()
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Search accounts by username or display name
     */
    public Page<SocialAccountResponseDto> searchByUsernameOrDisplayName(
            Long companyId, String searchTerm, Pageable pageable) {
        return jpaRepository.searchByUsernameOrDisplayName(companyId, searchTerm, pageable)
                .map(mapper::toResponseDto);
    }

    /**
     * Find accounts by company and platform
     */
    public List<SocialAccountResponseDto> findByCompanyAndPlatform(
            Long companyId, Long socialNetworkId) {
        return jpaRepository.findByCompanyAndPlatform(companyId, socialNetworkId)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Find accounts by company and status
     */
    public List<SocialAccountResponseDto> findByCompanyAndStatus(
            Long companyId, SocialAccountJpaEntity.ConnectionStatusEnum status) {
        return jpaRepository.findByCompanyAndStatus(companyId, status)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Find accounts by company and active status
     */
    public List<SocialAccountResponseDto> findByCompanyAndActiveStatus(
            Long companyId, Boolean active) {
        return jpaRepository.findByCompanyAndActiveStatus(companyId, active)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Get total storage usage for company
     */
    public Long getTotalStorageUsageByCompany(Long companyId) {
        return jpaRepository.getTotalStorageUsageByCompany(companyId);
    }

    /**
     * Find recently active accounts by company
     */
    public List<SocialAccountResponseDto> findRecentlyActiveByCompany(
            Long companyId, LocalDateTime since) {
        return jpaRepository.findRecentlyActiveByCompany(companyId, since)
                .stream()
                .map(mapper::toResponseDto)
                .toList();
    }

    /**
     * Soft delete account
     */
    public void softDelete(Long id) {
        jpaRepository.softDelete(id);
    }

    /**
     * Hard delete account (use with caution)
     */
    public void deleteById(Long id) {
        jpaRepository.deleteById(id);
    }

    /**
     * Connect new social account
     */
    public SocialAccountResponseDto connectSocialAccount(
            String companyId,
            Long socialNetworkId,
            String username,
            String accessToken,
            String refreshToken,
            String tokenType) {
        
        SocialAccountJpaEntity entity = mapper.createEntityFromConnectCommand(
                companyId, socialNetworkId, username, accessToken, refreshToken, tokenType);
        
        return save(entity);
    }

    /**
     * Update social account
     */
    public SocialAccountResponseDto updateSocialAccount(
            Long id,
            String displayName,
            String bio,
            String location,
            String website,
            String profilePhotoUrl,
            String contactPhone,
            String contactEmail,
            String category,
            java.util.Map<String, Object> automationConfig,
            String responsibleUserId) {
        
        Optional<SocialAccountJpaEntity> entityOpt = jpaRepository.findById(id);
        if (entityOpt.isEmpty()) {
            throw new IllegalArgumentException("Social account not found with ID: " + id);
        }
        
        SocialAccountJpaEntity entity = entityOpt.get();
        mapper.updateEntityFromRequest(entity, displayName, bio, location, website,
                profilePhotoUrl, contactPhone, contactEmail, category, automationConfig, responsibleUserId);
        
        return save(entity);
    }

    /**
     * Disconnect social account
     */
    public void disconnectSocialAccount(Long id) {
        Optional<SocialAccountJpaEntity> entityOpt = jpaRepository.findById(id);
        if (entityOpt.isEmpty()) {
            throw new IllegalArgumentException("Social account not found with ID: " + id);
        }
        
        SocialAccountJpaEntity entity = entityOpt.get();
        entity.setConnectionStatus(SocialAccountJpaEntity.ConnectionStatusEnum.INACTIVE);
        entity.setActive(false);
        entity.setLastSyncDate(LocalDateTime.now());
        
        jpaRepository.save(entity);
    }

    /**
     * Toggle social account active status
     */
    public SocialAccountResponseDto toggleActiveStatus(Long id) {
        Optional<SocialAccountJpaEntity> entityOpt = jpaRepository.findById(id);
        if (entityOpt.isEmpty()) {
            throw new IllegalArgumentException("Social account not found with ID: " + id);
        }
        
        SocialAccountJpaEntity entity = entityOpt.get();
        entity.setActive(!entity.getActive());
        
        return save(entity);
    }

    /**
     * Update sync timestamp
     */
    public void updateSyncTimestamp(Long id) {
        Optional<SocialAccountJpaEntity> entityOpt = jpaRepository.findById(id);
        if (entityOpt.isPresent()) {
            SocialAccountJpaEntity entity = entityOpt.get();
            entity.setLastSyncDate(LocalDateTime.now());
            jpaRepository.save(entity);
        }
    }

    /**
     * Update connection status
     */
    public void updateConnectionStatus(Long id, SocialAccountJpaEntity.ConnectionStatusEnum status) {
        Optional<SocialAccountJpaEntity> entityOpt = jpaRepository.findById(id);
        if (entityOpt.isPresent()) {
            SocialAccountJpaEntity entity = entityOpt.get();
            entity.setConnectionStatus(status);
            entity.setLastSyncDate(LocalDateTime.now());
            jpaRepository.save(entity);
        }
    }

    /**
     * Update account metrics
     */
    public void updateMetrics(Long id, java.util.Map<String, Object> metrics) {
        Optional<SocialAccountJpaEntity> entityOpt = jpaRepository.findById(id);
        if (entityOpt.isPresent()) {
            SocialAccountJpaEntity entity = entityOpt.get();
            entity.setMetrics(metrics);
            entity.setLastSyncDate(LocalDateTime.now());
            jpaRepository.save(entity);
        }
    }

    /**
     * Update authentication tokens
     */
    public void updateTokens(Long id, java.util.Map<String, Object> tokens) {
        Optional<SocialAccountJpaEntity> entityOpt = jpaRepository.findById(id);
        if (entityOpt.isPresent()) {
            SocialAccountJpaEntity entity = entityOpt.get();
            entity.setTokens(tokens);
            entity.setConnectionStatus(SocialAccountJpaEntity.ConnectionStatusEnum.ACTIVE);
            entity.setLastSyncDate(LocalDateTime.now());
            jpaRepository.save(entity);
        }
    }
}
