package com.interplug.qcast.batch.master;

import com.interplug.qcast.biz.storeFavorite.StoreFavoriteService;
import com.interplug.qcast.biz.storeFavorite.dto.StoreFavoriteRequest;
import com.interplug.qcast.biz.user.UserService;
import com.interplug.qcast.biz.user.dto.StoreRequest;
import com.interplug.qcast.biz.user.dto.StoreSyncResponse;
import com.interplug.qcast.biz.user.dto.UserRequest;
import com.interplug.qcast.util.InterfaceQsp;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.job.builder.JobBuilder;
import org.springframework.batch.core.repository.JobRepository;
import org.springframework.batch.core.step.builder.StepBuilder;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.ListItemReader;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.transaction.PlatformTransactionManager;

@Configuration
@Slf4j
public class StoreJobConfiguration implements JobExecutionListener {

  private final InterfaceQsp interfaceQsp;
  private final UserService userService;
  private final StoreFavoriteService storeFavService;

  @Value("${qsp.master-store-batch-url}")
  private String qspMasterStoreBatchUrl;

  private StoreSyncResponse storeSyncResponse;

  public StoreJobConfiguration(
      InterfaceQsp interfaceQsp, UserService userService, StoreFavoriteService storeFavService) {
    this.interfaceQsp = interfaceQsp;
    this.userService = userService;
    this.storeFavService = storeFavService;
  }

  @Override
  public void beforeJob(JobExecution jobExecution) {
    log.info("Job 시작: 초기화 메서드 호출 중...");
    try {
      this.storeSyncResponse =
          interfaceQsp.callApiData(
              HttpMethod.GET, qspMasterStoreBatchUrl, null, StoreSyncResponse.class);
      log.info("API 호출 완료, 항목 수: {}", this.storeSyncResponse.getStoreList().size());
    } catch (Exception e) {
      log.error("storeSyncResponse 갱신 중 오류: {}", e.getMessage());
    }
  }

  @Bean
  public Job storeAdditionalJob(
      JobRepository jobRepository, Step storeStep, Step userStep, Step favoriteStep) {
    return new JobBuilder("storeAdditionalJob", jobRepository)
        .start(storeStep)
        .next(userStep)
        .next(favoriteStep)
        .listener(this)
        .build();
  }

  private <T> Step buildStep(
      String stepName,
      JobRepository jobRepository,
      PlatformTransactionManager transactionManager,
      ItemReader<T> reader,
      ItemWriter<T> writer) {
    return new StepBuilder(stepName, jobRepository)
        .<T, T>chunk(10, transactionManager)
        .reader(reader)
        .writer(writer)
        .build();
  }

  @Bean
  public Step storeStep(
      JobRepository jobRepository, PlatformTransactionManager transactionManager) {
    return buildStep(
        "storeStep",
        jobRepository,
        transactionManager,
        storeListReader(),
        createWriter(
            (items) -> {
              try {
                log.debug("Store batch processing {} items", items.size());
                userService.setStoreBatch(items);
                log.debug("Successfully processed store batch");
              } catch (Exception e) {
                log.error("Error processing store batch: {}", e.getMessage(), e);
                throw new RuntimeException("Failed to process store batch", e);
              }
            },
            "store"));
  }

  @Bean
  public Step userStep(JobRepository jobRepository, PlatformTransactionManager transactionManager) {
    return buildStep(
        "userStep",
        jobRepository,
        transactionManager,
        userListReader(),
        createWriter(
            (items) -> {
              try {
                log.debug("User batch processing {} items", items.size());
                userService.setUserBatch(items);
                log.debug("Successfully processed user batch");
              } catch (Exception e) {
                log.error("Error processing user batch: {}", e.getMessage(), e);
                throw new RuntimeException("Failed to process user batch", e);
              }
            },
            "user"));
  }

  @Bean
  public Step favoriteStep(
      JobRepository jobRepository, PlatformTransactionManager transactionManager) {
    return buildStep(
        "favoriteStep",
        jobRepository,
        transactionManager,
        storeFavListReader(),
        createWriter(
            (items) -> {
              try {
                log.debug("Favorite batch processing {} items", items.size());
                storeFavService.setStoreFavoriteBatch(items);
                log.debug("Successfully processed favorite batch");
              } catch (Exception e) {
                log.error("Error processing favorite batch: {}", e.getMessage(), e);
                throw new RuntimeException("Failed to process favorite batch", e);
              }
            },
            "favorite"));
  }

  private <T> ListItemReader<T> createReader(List<T> items, String readerName) {
    log.info("{}Reader 호출됨...", readerName);
    return new ListItemReader<>(items != null ? items : Collections.emptyList());
  }

  @Bean
  @StepScope
  public ListItemReader<StoreRequest> storeListReader() {
    return createReader(
        storeSyncResponse != null ? storeSyncResponse.getStoreList() : null, "store");
  }

  @Bean
  @StepScope
  public ListItemReader<UserRequest> userListReader() {
    return createReader(storeSyncResponse != null ? storeSyncResponse.getUserList() : null, "user");
  }

  @Bean
  @StepScope
  public ListItemReader<StoreFavoriteRequest> storeFavListReader() {
    return createReader(
        storeSyncResponse != null ? storeSyncResponse.getStoreFavList() : null, "storeFav");
  }

  private <T> ItemWriter<T> createWriter(Consumer<List<T>> processor, String writerName) {
    return items -> {
      try {
        List<T> itemList = (List<T>) items.getItems();
        processor.accept(itemList);
        log.info("{}Writer: {} items 처리 완료", writerName, items.size());
      } catch (Exception e) {
        log.error("{}Writer 오류: {}", writerName, e.getMessage());
        throw e;
      }
    };
  }
}
