package com.erp.provisioning;

import com.erp.tenant.ReservedSubdomains;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ResponseStatusException;

import java.util.regex.Pattern;

/**
 * `/api/admin/provisioning/*` 계열 엔드포인트 공통 권한 가드.
 *
 *  - 호스트 격리: 테넌트 서브도메인(qnc.invyone.com 등)에서 호출하면 무조건 403.
 *    프로비저닝 plane 은 solution/admin/localhost/베이스 도메인 같은 "관리 호스트" 에서만 동작.
 *    (한 번 SUPER_ADMIN 토큰이 새도 임의의 테넌트 사이트에서는 회사를 만들 수 없게 막음)
 *  - 프로덕션 (tenant.provisioning.require-super-admin=true): SUPER_ADMIN 만 통과
 *  - 개발 (기본값 false): JWT 없어도 통과 (curl 테스트). 다른 role 은 여전히 차단
 *
 * JwtAuthenticationFilter 가 request.getAttribute("user_type"), "user_id" 를 세팅한다.
 */
@Component
@Slf4j
public class SuperAdminGuard {

    private static final Pattern IPV4 = Pattern.compile("^\\d{1,3}(\\.\\d{1,3}){3}$");

    @Value("${tenant.provisioning.require-super-admin:false}")
    private boolean requireSuperAdmin;

    public void enforce(HttpServletRequest request) {
        // 1) 호스트 격리 — role 보다 먼저 체크. 어떤 role 도 테넌트 사이트에서는 통과 못 함.
        String host = request.getHeader("Host");
        if (isTenantHost(host)) {
            log.warn("[ProvisioningGuard] blocked tenant-host call: host={} path={} userType={}",
                    host, request.getRequestURI(), request.getAttribute("user_type"));
            throw new ResponseStatusException(HttpStatus.FORBIDDEN,
                    "Provisioning is only available on the management site");
        }

        // 2) role 체크
        String userType = (String) request.getAttribute("user_type");
        if ("SUPER_ADMIN".equals(userType)) return;
        if (!requireSuperAdmin && userType == null) {
            log.warn("[ProvisioningGuard] anonymous access allowed in dev mode");
            return;
        }
        throw new ResponseStatusException(HttpStatus.FORBIDDEN, "SUPER_ADMIN only");
    }

    /** 감사 로그에 기록할 actor user_id. 개발모드에서 JWT 없으면 "dev-anonymous". */
    public String actorUserId(HttpServletRequest request) {
        String userId = (String) request.getAttribute("user_id");
        return userId == null ? "dev-anonymous" : userId;
    }

    /** 감사 로그에 기록할 호스트 (Host 헤더 그대로, 포트 포함). null safe. */
    public String requestHost(HttpServletRequest request) {
        String host = request.getHeader("Host");
        return host == null ? "" : host;
    }

    /**
     * "테넌트 사이트에서 온 요청인지" 판단. SubdomainResolverFilter.extractSubdomain 와 같은 규칙.
     *  - localhost / IP / 베이스 도메인 → false (관리 호스트)
     *  - solution.invyone.com 등 예약어 prefix → false (관리 호스트)
     *  - qnc.invyone.com / test02.invyone.com 같은 실제 테넌트 → true
     */
    public static boolean isTenantHost(String host) {
        if (host == null || host.isBlank()) return false;

        int colon = host.indexOf(':');
        if (colon != -1) host = host.substring(0, colon);
        host = host.toLowerCase();

        if ("localhost".equals(host)) return false;
        if (IPV4.matcher(host).matches()) return false;

        String[] parts = host.split("\\.");
        if (parts.length == 2) {
            // {sub}.localhost (dev)
            if (!"localhost".equals(parts[1])) return false;
            String first = parts[0];
            if (first.isEmpty()) return false;
            return !ReservedSubdomains.VALUES.contains(first);
        }
        if (parts.length < 3) return false;

        String first = parts[0];
        return !ReservedSubdomains.VALUES.contains(first);
    }
}
