package com.zioinfo.mes.uiws.system.service;

import com.zioinfo.mes.uiws.common.UiwsApiException;
import com.zioinfo.mes.uiws.common.UiwsErrorCode;
import com.zioinfo.mes.uiws.system.dto.PageResponse;
import com.zioinfo.mes.uiws.system.dto.ProgramDto;
import com.zioinfo.mes.uiws.system.dto.ProgramSaveDto;
import com.zioinfo.mes.uiws.system.mapper.MenuMapper;
import com.zioinfo.mes.uiws.system.mapper.ProgramMapper;
import com.zioinfo.mes.uiws.system.model.SysProgram;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/** 2.8 프로그램(programs) CRUD + 검색팝업 + 다중삭제. */
@Service
@RequiredArgsConstructor
public class ProgramService {

    private final ProgramMapper programMapper;
    private final MenuMapper menuMapper;

    @Transactional(readOnly = true)
    public PageResponse<ProgramDto> list(String keyword, String programType, int page, int size) {
        List<ProgramDto> content = programMapper.search(keyword, programType, page * size, size)
                .stream().map(this::toDto).toList();
        return PageResponse.of(content, programMapper.countSearch(keyword, programType), page, size);
    }

    @Transactional(readOnly = true)
    public List<ProgramDto> searchPopup(String keyword) {
        return programMapper.searchActive(keyword).stream().map(this::toDto).toList();
    }

    @Transactional(readOnly = true)
    public ProgramDto get(String programId) {
        return toDto(find(programId));
    }

    @Transactional
    public ProgramDto create(ProgramSaveDto dto) {
        if (programMapper.existsById(dto.programId())) {
            throw new UiwsApiException(UiwsErrorCode.DUPLICATE_KEY, "이미 존재하는 프로그램 ID입니다.");
        }
        SysProgram p = new SysProgram();
        p.setProgramId(dto.programId());
        apply(p, dto);
        p.setCreatedBy(SysActor.id());
        programMapper.insert(p);
        return toDto(find(dto.programId()));
    }

    @Transactional
    public ProgramDto update(String programId, ProgramSaveDto dto) {
        SysProgram p = find(programId);
        apply(p, dto);
        p.setUpdatedBy(SysActor.id());
        programMapper.update(p);
        return toDto(find(programId));
    }

    @Transactional
    public void delete(List<String> ids) {
        for (String id : ids) {
            if (!programMapper.existsById(id)) {
                throw new UiwsApiException(UiwsErrorCode.PROGRAM_NOT_FOUND);
            }
            if (menuMapper.existsByProgramId(id)) {
                throw new UiwsApiException(UiwsErrorCode.RESOURCE_IN_USE,
                        "메뉴에서 참조 중인 프로그램은 삭제할 수 없습니다: " + id);
            }
            programMapper.deleteById(id);
        }
    }

    private void apply(SysProgram p, ProgramSaveDto dto) {
        p.setProgramNm(dto.programNm());
        p.setProgramType(dto.programType());
        p.setProgramUrl(dto.programUrl());
        p.setCategory(dto.category());
        p.setUseYn(dto.useYn());
    }

    private ProgramDto toDto(SysProgram p) {
        return new ProgramDto(p.getProgramId(), p.getProgramNm(), p.getProgramType(),
                p.getProgramUrl(), p.getCategory(), p.getUseYn());
    }

    private SysProgram find(String programId) {
        SysProgram p = programMapper.findById(programId);
        if (p == null) {
            throw new UiwsApiException(UiwsErrorCode.PROGRAM_NOT_FOUND);
        }
        return p;
    }
}
