package com.devjob.job.service;

import com.devjob.job.domain.Company;
import com.devjob.job.domain.Job;
import com.devjob.job.domain.JobStatus;
import com.devjob.job.dto.JobCreateRequest;
import com.devjob.job.dto.JobResponse;
import com.devjob.job.dto.JobSearchRequest;
import com.devjob.job.dto.JobUpdateRequest;
import com.devjob.common.dto.PageResponse;
import com.devjob.common.exception.BusinessException;
import com.devjob.common.exception.ErrorCode;
import com.devjob.job.repository.CompanyRepository;
import com.devjob.job.repository.JobRepository;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * EP07: 시즌1 EP13~EP27의 JobService를 옮겨왔다.
 * Redis 캐시(@Cacheable)는 시즌1 전용 인프라이므로 일단 제거하고,
 * 핵심 CRUD/검색 로직만 유지한다.
 */
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class JobService {

    private final JobRepository jobRepository;
    private final CompanyRepository companyRepository;

    @Transactional
    public JobResponse create(JobCreateRequest req, Long registeredBy) {
        Company company = companyRepository.findById(req.companyId())
                .orElseThrow(() -> new BusinessException(ErrorCode.COMPANY_NOT_FOUND));

        Job job = new Job();
        job.setCompany(company);
        job.setRegisteredBy(registeredBy);
        job.setTitle(req.title());
        job.setDescription(req.description());
        job.setSalary(req.salary());
        job.setStatus(JobStatus.OPEN);
        job.setDeadline(req.deadline());
        return JobResponse.from(jobRepository.save(job));
    }

    public Optional<JobResponse> findById(Long id) {
        return jobRepository.findById(id).map(JobResponse::from);
    }

    public PageResponse<JobResponse> findByStatus(JobStatus status, Pageable pageable) {
        return PageResponse.of(jobRepository.findByStatusWithCompany(status, pageable).map(JobResponse::from));
    }

    public PageResponse<JobResponse> search(JobSearchRequest request, Pageable pageable) {
        return PageResponse.of(jobRepository.findAll(request.toSpecification(), pageable).map(JobResponse::from));
    }

    @Transactional
    public JobResponse update(Long id, JobUpdateRequest req) {
        Job job = jobRepository.findById(id)
                .orElseThrow(() -> new BusinessException(ErrorCode.JOB_NOT_FOUND));
        job.update(req.title(), req.description(), req.salary(), req.deadline());
        return JobResponse.from(job);
    }

    @Transactional
    public void delete(Long id) {
        if (!jobRepository.existsById(id)) {
            throw new BusinessException(ErrorCode.JOB_NOT_FOUND);
        }
        jobRepository.deleteById(id);
    }
}
