package com.spring.infra.batch;

import org.springframework.batch.core.Job;
import org.springframework.batch.core.configuration.DuplicateJobException;
import org.springframework.batch.core.configuration.JobRegistry;
import org.springframework.batch.core.configuration.support.ReferenceJobFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Component;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Component
@RequiredArgsConstructor
public class BatchJobInfoBeanPostProcessor implements BeanPostProcessor {

    private final BatchJobInfoService batchJobInfoService;
    private final JobRegistry jobRegistry;

    @Override
    @Nullable
    public Object postProcessBeforeInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
        processBatchJobInfoAnnotations(bean, beanName);
        return bean;
    }

    @Override
    @Nullable
    public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
        if (bean instanceof AbstractBatch) {
            AbstractBatch abstractBatch = (AbstractBatch) bean;
            Job job = abstractBatch.createJob();
            String jobName = job.getName();
            if (!jobRegistry.getJobNames().contains(jobName)) {
                try {
                    jobRegistry.register(new ReferenceJobFactory(job));
                } catch (DuplicateJobException e) {
                    log.warn("Unexpected DuplicateJobException for job: {}", jobName, e);
                }
            }
        }
        return bean;
    }

    private void processBatchJobInfoAnnotations(Object bean, String beanName) {
        if (bean.getClass().isAnnotationPresent(BatchJobInfo.class)) {
            BatchJobInfo batchJobInfo = bean.getClass().getAnnotation(BatchJobInfo.class);
            batchJobInfoService.setBatchJobInfoData(removeScopedTargetPrefix(beanName), batchJobInfo);
        }
    }

    private String removeScopedTargetPrefix(String beanName) {
        return beanName.startsWith("scopedTarget.") ? beanName.substring("scopedTarget.".length()) : beanName;
    }

}
