package com.eactive.eai.rms.onl.apim.obp;

import com.eactive.apim.portal.app.entity.Credential;
import com.eactive.apim.portal.app.repository.CredentialRepository;
import com.eactive.apim.portal.apispec.entity.ApiSpecInfo;
import com.eactive.apim.portal.portalorg.entity.PortalOrg;
import com.eactive.eai.data.entity.onl.message.QEAIMessageEntity;
import com.eactive.eai.data.entity.onl.stdmessage.QStandardMessageInfo;
import com.eactive.eai.rms.data.entity.onl.apim.portalorg.PortalOrgRepository;
import com.querydsl.core.Tuple;
import com.querydsl.jpa.impl.JPAQueryFactory;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * OBP API 목록 조회 Service
 *
 * <p>APIGW 데이터소스의 TSEAIHE01, TSEAIHS04 테이블에서 API 정보 조회</p>
 */
@Service
public class ObpApiService {

    @PersistenceContext
    private EntityManager entityManager;

    private final PortalOrgRepository portalOrgRepository;
    private final CredentialRepository credentialRepository;

    public ObpApiService(PortalOrgRepository portalOrgRepository, CredentialRepository credentialRepository) {
        this.portalOrgRepository = portalOrgRepository;
        this.credentialRepository = credentialRepository;
    }

    private JPAQueryFactory getQueryFactory() {
        return new JPAQueryFactory(entityManager);
    }

    /**
     * 전체 API 목록 조회
     *
     * @return API 목록
     */
    public List<ObpApiDTO> findAllApis() {
        QEAIMessageEntity he01 = QEAIMessageEntity.eAIMessageEntity;
        QStandardMessageInfo hs04 = QStandardMessageInfo.standardMessageInfo;

        List<Tuple> results = getQueryFactory()
                .select(
                        he01.eaisvcname,
                        he01.eaisvcdesc,
                        he01.useyn,
                        he01.authtype,
                        hs04.apifullpath
                )
                .from(he01)
                .leftJoin(hs04).on(he01.eaisvcname.eq(hs04.eaisvcname))
                .orderBy(he01.eaisvcname.asc())
                .fetch();

        return results.stream()
                .map(this::toDto)
                .collect(Collectors.toList());
    }

    /**
     * Tuple을 DTO로 변환
     */
    private ObpApiDTO toDto(Tuple tuple) {
        QEAIMessageEntity he01 = QEAIMessageEntity.eAIMessageEntity;
        QStandardMessageInfo hs04 = QStandardMessageInfo.standardMessageInfo;

        String eaisvcname = tuple.get(he01.eaisvcname);
        String eaisvcdesc = tuple.get(he01.eaisvcdesc);
        String useyn = tuple.get(he01.useyn);
        String authtype = tuple.get(he01.authtype);
        String apifullpath = tuple.get(hs04.apifullpath);

        // APIFULLPATH 파싱: "POST|/mapi/kjbank/..." -> method="POST", url="/mapi/kjbank/..."
        String method = null;
        String url = null;
        if (StringUtils.isNotBlank(apifullpath) && apifullpath.contains("|")) {
            int pipeIndex = apifullpath.indexOf('|');
            method = apifullpath.substring(0, pipeIndex);
            url = apifullpath.substring(pipeIndex + 1);
        }

        // USEYN이 "1"이면 enabled = true
        boolean enabled = "1".equals(useyn);

        // RequiredAuthentication 매핑
        ObpApiDTO.RequiredAuthentication reqAuth = mapAuthType(authtype);

        // Status 매핑
        ObpApiDTO.Status status = mapStatus(enabled);

        return ObpApiDTO.builder()
                .id(null)
                .apiId(eaisvcname)
                .name(eaisvcdesc)
                .enabled(enabled)
                .urlPattern(url)
                .method(method)
                .requiredAuthentication(reqAuth)
                .status(status)
                .build();
    }

    /**
     * 인증 타입을 RequiredAuthentication으로 매핑
     *
     * @param authtype TSEAIHE01.AUTHTYPE 값
     * @return RequiredAuthentication 객체
     */
    private ObpApiDTO.RequiredAuthentication mapAuthType(String authtype) {
        if ("api_key".equalsIgnoreCase(authtype)) {
            return ObpApiDTO.RequiredAuthentication.builder()
                    .key("API_KEY")
                    .name("APP키를 이용한 인증")
                    .build();
        } else if ("oauth".equalsIgnoreCase(authtype) || "ca".equalsIgnoreCase(authtype)) {
            return ObpApiDTO.RequiredAuthentication.builder()
                    .key("OAUTH2")
                    .name("OAuth Ver.2 인증")
                    .build();
        } else {
            return ObpApiDTO.RequiredAuthentication.builder()
                    .key("NONE")
                    .name("인증없이 사용")
                    .build();
        }
    }

    /**
     * enabled 값을 Status로 매핑
     *
     * @param enabled 활성화 여부
     * @return Status 객체
     */
    private ObpApiDTO.Status mapStatus(boolean enabled) {
        if (enabled) {
            return ObpApiDTO.Status.builder()
                    .key("RUNNING")
                    .name("서비스 중")
                    .deployed(true)
                    .build();
        } else {
            return ObpApiDTO.Status.builder()
                    .key("SUSPEND")
                    .name("서비스 일시 중지")
                    .deployed(false)
                    .build();
        }
    }

    /**
     * 기관코드에 해당하는 법인이 이용하는 API 목록 조회
     *
     * <p>활성 앱(appstatus='1')의 API만 조회</p>
     *
     * @param orgCode 기관코드 (OBP 파트너코드)
     * @return API 목록 (기관 미존재 시 빈 리스트)
     */
    public List<ObpApiDTO> findApisByOrgCode(String orgCode) {
        // 1. 기관코드로 기관 조회
        Optional<PortalOrg> orgOpt = portalOrgRepository.findByOrgCode(orgCode);
        if (!orgOpt.isPresent()) {
            return Collections.emptyList();
        }

        PortalOrg org = orgOpt.get();

        // 2. 해당 기관의 활성 앱 조회 (appstatus='1')
        List<Credential> activeApps = credentialRepository.findActiveAppsByOrgIds(
                Collections.singletonList(org.getId()));
        if (activeApps.isEmpty()) {
            return Collections.emptyList();
        }

        // 3. 앱들의 API ID 목록 수집
        Set<String> apiIds = activeApps.stream()
                .flatMap(app -> app.getApiList().stream())
                .map(ApiSpecInfo::getApiId)
                .collect(Collectors.toSet());
        if (apiIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 4. 해당 API만 조회
        QEAIMessageEntity he01 = QEAIMessageEntity.eAIMessageEntity;
        QStandardMessageInfo hs04 = QStandardMessageInfo.standardMessageInfo;

        List<Tuple> results = getQueryFactory()
                .select(
                        he01.eaisvcname,
                        he01.eaisvcdesc,
                        he01.useyn,
                        he01.authtype,
                        hs04.apifullpath
                )
                .from(he01)
                .leftJoin(hs04).on(he01.eaisvcname.eq(hs04.eaisvcname))
                .where(he01.eaisvcname.in(apiIds))
                .orderBy(he01.eaisvcname.asc())
                .fetch();

        return results.stream()
                .map(this::toDto)
                .collect(Collectors.toList());
    }
}
