package com.zioinfo.cms.delivery;

import com.zioinfo.cms.content.CmsContent;
import com.zioinfo.cms.content.mapper.ContentMapper;
import com.zioinfo.cms.common.CryptoUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;

import java.util.List;

/**
 * 헤드리스 delivery 서비스.
 *
 * <p>보안 불변 규칙: published 상태만 공개. 프리뷰는 HMAC 기반 토큰(contentId+만료) 검증.
 * 토큰은 CryptoUtil(AES-GCM)로 봉인 — "contentId:expiryEpoch" 평문을 암호화한 값.
 */
@Service
@RequiredArgsConstructor
public class DeliveryService {

    private static final long PREVIEW_TTL_MS = 3600_000; // 1시간

    private final ContentMapper contentMapper;
    private final CryptoUtil crypto;

    public List<CmsContent> listPublished(String contentType, String locale) {
        return contentMapper.findAll(contentType, "PUBLISHED", locale, null);
    }

    public CmsContent getPublished(String slug, String locale) {
        CmsContent c = contentMapper.findPublishedBySlug(slug, locale);
        if (c == null) {
            throw new RuntimeException("ERR-CMS-DELIVERY-404: 발행된 콘텐츠 없음");
        }
        return c;
    }

    public CmsContent preview(Long id, String token) {
        if (!verifyToken(id, token)) {
            throw new RuntimeException("ERR-CMS-DELIVERY-403: 유효하지 않거나 만료된 프리뷰 토큰");
        }
        CmsContent c = contentMapper.findById(id);
        if (c == null) {
            throw new RuntimeException("ERR-CMS-DELIVERY-404: 콘텐츠 없음");
        }
        return c;
    }

    public String issuePreviewToken(Long id) {
        if (contentMapper.findById(id) == null) {
            throw new RuntimeException("ERR-CMS-DELIVERY-404: 콘텐츠 없음");
        }
        long expiry = System.currentTimeMillis() + PREVIEW_TTL_MS;
        return crypto.encrypt(id + ":" + expiry);
    }

    private boolean verifyToken(Long id, String token) {
        try {
            String plain = crypto.decrypt(token);
            if (plain == null || plain.isBlank()) return false;
            String[] parts = plain.split(":");
            if (parts.length != 2) return false;
            long tokenId = Long.parseLong(parts[0]);
            long expiry = Long.parseLong(parts[1]);
            return tokenId == id && expiry >= System.currentTimeMillis();
        } catch (Exception e) {
            return false;
        }
    }
}
