/**
 * conformance.ts — 응답 적합성 검증 유틸리티
 *
 * closebook: response-conformance
 * Zod 스키마로 Hono 응답의 상태코드 + Content-Type + 바디 적합성 검사.
 * Hono app.request() 기반, 실제 HTTP 서버 불필요.
 */

import { z } from "zod"

export interface ConformanceResult {
	ok: boolean
	statusOk: boolean
	bodyOk: boolean
	contentTypeOk: boolean
	violations: Array<{ path: string; message: string; value?: unknown }>
}

// 응답 적합성 검증 — 상태코드 + Content-Type + 바디 스키마
export function checkResponseConformance(cfg: {
	status: number
	headers?: Record<string, string>
	body: unknown
	schema: z.ZodType
	allowedStatuses?: number[]
}): ConformanceResult {
	const { status, headers, body, schema, allowedStatuses = [200, 201] } = cfg
	const violations: ConformanceResult["violations"] = []

	// 1. 상태 코드 검사
	const statusOk = allowedStatuses.length === 0 || allowedStatuses.includes(status)
	if (!statusOk) {
		violations.push({
			path: "status",
			message: `Expected one of ${allowedStatuses.join("/")}, got ${status}`,
		})
	}

	// 2. Content-Type 검사
	const contentType = headers?.["content-type"] ?? ""
	const contentTypeOk = !headers || contentType.includes("application/json")
	if (!contentTypeOk) {
		violations.push({
			path: "content-type",
			message: `Expected application/json, got ${contentType}`,
		})
	}

	// 3. 바디 스키마 검증 (Zod)
	const parsed = schema.safeParse(body)
	const bodyOk = parsed.success
	if (!parsed.success) {
		for (const issue of parsed.error.issues) {
			violations.push({
				path: issue.path.join(".") || "(root)",
				message: issue.message,
			})
		}
	}

	return {
		ok: violations.length === 0,
		statusOk,
		bodyOk,
		contentTypeOk,
		violations,
	}
}

// Hono Response에서 적합성 검증
export async function checkHonoResponse(
	res: Response,
	schema: z.ZodType,
	allowedStatuses?: number[],
): Promise<ConformanceResult> {
	const body = await res.json()
	const headers: Record<string, string> = {}
	res.headers.forEach((v, k) => {
		headers[k] = v
	})
	return checkResponseConformance({
		status: res.status,
		headers,
		body,
		schema,
		allowedStatuses,
	})
}
