package com.social.media.service.impl;

import com.social.media.domain.entity.Company;
import com.social.media.dto.CompanyDto;
import com.social.media.mapper.CompanyMapper;
import com.social.media.repository.CompanyRepository;
import com.social.media.service.CompanyService;
import com.social.media.domain.shared.PageResponse;
import jakarta.persistence.EntityNotFoundException;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

import java.util.Optional;

@Service
@Transactional
public class CompanyServiceImpl implements CompanyService {

    @Autowired
    private CompanyRepository companyRepository;
    
    @Autowired
    private CompanyMapper companyMapper;

    @Override
    public PageResponse<CompanyDto> getAllCompanies(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
        Page<Company> companiesPage = companyRepository.findAll(pageable);
        
        return new PageResponse<>(
                companyMapper.toDtoList(companiesPage.getContent()),
                companiesPage.getTotalElements(),
                companiesPage.getTotalPages(),
                companiesPage.getSize(),
                companiesPage.getNumber(),
                companiesPage.isFirst(),
                companiesPage.isLast()
        );
    }

    @Override
    public CompanyDto getCompanyById(Long id) {
        Company company = companyRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("Empresa não encontrada com ID: " + id));
        return companyMapper.toDto(company);
    }

    @Override
    public CompanyDto createCompany(CompanyDto companyDto) {
        // Validate unique constraints
        if (existsByCnpj(companyDto.getCnpj())) {
            throw new IllegalArgumentException("CNPJ já está em uso: " + companyDto.getCnpj());
        }
        
        if (existsByEmail(companyDto.getEmail())) {
            throw new IllegalArgumentException("Email já está em uso: " + companyDto.getEmail());
        }
        
        Company company = companyMapper.createEntity(companyDto);
        Company savedCompany = companyRepository.save(company);
        return companyMapper.toDto(savedCompany);
    }

    @Override
    public CompanyDto updateCompany(Long id, CompanyDto companyDto) {
        Company existingCompany = companyRepository.findById(id)
                .orElseThrow(() -> new EntityNotFoundException("Empresa não encontrada com ID: " + id));
        
        // Validate unique constraints (excluding current company)
        if (!existingCompany.getCnpj().equals(companyDto.getCnpj()) && 
            companyRepository.existsByCnpjAndIdNot(companyDto.getCnpj(), id)) {
            throw new IllegalArgumentException("CNPJ já está em uso por outra empresa: " + companyDto.getCnpj());
        }
        
        if (!existingCompany.getEmail().equals(companyDto.getEmail()) && 
            companyRepository.existsByEmailAndIdNot(companyDto.getEmail(), id)) {
            throw new IllegalArgumentException("Email já está em uso por outra empresa: " + companyDto.getEmail());
        }
        
        companyMapper.updateEntity(existingCompany, companyDto);
        Company updatedCompany = companyRepository.save(existingCompany);
        return companyMapper.toDto(updatedCompany);
    }

    @Override
    public void deleteCompany(Long id) {
        if (!companyRepository.existsById(id)) {
            throw new EntityNotFoundException("Empresa não encontrada com ID: " + id);
        }
        companyRepository.deleteById(id);
    }

    @Override
    public PageResponse<CompanyDto> searchCompanies(String query, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
        Page<Company> companiesPage = companyRepository.searchCompanies(query, pageable);
        
        return new PageResponse<>(
                companyMapper.toDtoList(companiesPage.getContent()),
                companiesPage.getTotalElements(),
                companiesPage.getTotalPages(),
                companiesPage.getSize(),
                companiesPage.getNumber(),
                companiesPage.isFirst(),
                companiesPage.isLast()
        );
    }

    @Override
    public PageResponse<CompanyDto> getCompaniesByStatus(String status, int page, int size) {
        try {
            Company.CompanyStatus companyStatus = Company.CompanyStatus.valueOf(status);
            Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
            Page<Company> companiesPage = companyRepository.findByStatus(companyStatus, pageable);
            
            return new PageResponse<>(
                    companyMapper.toDtoList(companiesPage.getContent()),
                    companiesPage.getTotalElements(),
                    companiesPage.getTotalPages(),
                    companiesPage.getSize(),
                    companiesPage.getNumber(),
                    companiesPage.isFirst(),
                    companiesPage.isLast()
            );
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Status inválido: " + status);
        }
    }

    @Override
    public PageResponse<CompanyDto> getCompaniesByPlan(String plan, int page, int size) {
        try {
            Company.CompanyPlan companyPlan = Company.CompanyPlan.valueOf(plan);
            Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
            Page<Company> companiesPage = companyRepository.findByPlan(companyPlan, pageable);
            
            return new PageResponse<>(
                    companyMapper.toDtoList(companiesPage.getContent()),
                    companiesPage.getTotalElements(),
                    companiesPage.getTotalPages(),
                    companiesPage.getSize(),
                    companiesPage.getNumber(),
                    companiesPage.isFirst(),
                    companiesPage.isLast()
            );
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Plano inválido: " + plan);
        }
    }

    @Override
    public PageResponse<CompanyDto> getActiveCompanies(int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("name").ascending());
        Page<Company> companiesPage = companyRepository.findActiveCompanies(pageable);
        
        return new PageResponse<>(
                companyMapper.toDtoList(companiesPage.getContent()),
                companiesPage.getTotalElements(),
                companiesPage.getTotalPages(),
                companiesPage.getSize(),
                companiesPage.getNumber(),
                companiesPage.isFirst(),
                companiesPage.isLast()
        );
    }

    @Override
    public CompanyDto getCompanyByCnpj(String cnpj) {
        Optional<Company> company = companyRepository.findByCnpj(cnpj);
        return company.map(companyMapper::toDto).orElse(null);
    }

    @Override
    public CompanyDto getCompanyByEmail(String email) {
        Optional<Company> company = companyRepository.findByEmail(email);
        return company.map(companyMapper::toDto).orElse(null);
    }

    @Override
    public CompanyDto getCompanyByCompanyCode(String companyCode) {
        Optional<Company> company = companyRepository.findByCompanyCode(companyCode);
        return company.map(companyMapper::toDto).orElse(null);
    }

    @Override
    public boolean existsByCnpj(String cnpj) {
        return companyRepository.findByCnpj(cnpj).isPresent();
    }

    @Override
    public boolean existsByEmail(String email) {
        return companyRepository.findByEmail(email).isPresent();
    }

    @Override
    public Long countActiveCompanies() {
        return companyRepository.countActiveCompanies();
    }

    @Override
    public Long countCompaniesByPlan(String plan) {
        try {
            Company.CompanyPlan companyPlan = Company.CompanyPlan.valueOf(plan);
            return companyRepository.countByPlan(companyPlan);
        } catch (IllegalArgumentException e) {
            throw new IllegalArgumentException("Plano inválido: " + plan);
        }
    }
}
