import { z } from "zod" import { geoipSettingsPatchSchema, geoipStatusDtoSchema, geoipUpdateSnapshotDtoSchema, type GeoipSettingsPatch } from "@mmapp/contracts/geoip" import { requestJson } from "@/shared/api/http-client" const statusSchema = geoipStatusDtoSchema.refine(status => status.ready === (status.countryLoaded && status.asnLoaded) && [status.settings.updatedAt, status.settings.lastCheckAt, status.settings.lastSuccessAt, status.settings.countryBuildAt, status.settings.asnBuildAt].every(value => value === null || Number.isFinite(Date.parse(value))), "Несогласованная готовность или время GeoIP") const updateSchema = z.object({ ok: z.boolean(), snapshot: geoipUpdateSnapshotDtoSchema }).refine(response => response.snapshot.v === 1 && Number.isFinite(Date.parse(response.snapshot.sampledAt)) && response.snapshot.checked >= 0 && response.snapshot.downloaded >= 0 && response.snapshot.skippedUnchanged >= 0 && response.snapshot.downloaded + response.snapshot.skippedUnchanged <= response.snapshot.checked && response.ok === (!response.snapshot.fatalError && response.snapshot.errors.length === 0), "Несогласованный результат GeoIP") function confirmed(schema: z.ZodType, raw: unknown): T { const parsed = schema.safeParse(raw) if (!parsed.success) throw new Error("Данные GeoIP не подтверждены: получен некорректный ответ сервера") return parsed.data } async function json(baseUrl: string, path: string, init?: RequestInit) { return requestJson(baseUrl, path, { ...init, signal: AbortSignal.any([...(init?.signal ? [init.signal] : []), AbortSignal.timeout(30_000)]) }) } export async function getGeoipStatus(baseUrl: string, init?: RequestInit) { return confirmed(statusSchema, await json(baseUrl, "/api/geoip", { ...init, method: "GET" })) } export async function putGeoipSettings(baseUrl: string, patch: GeoipSettingsPatch, init?: RequestInit) { const body = geoipSettingsPatchSchema.strict().parse(patch) const response = confirmed(z.object({ ok: z.literal(true), status: statusSchema }), await json(baseUrl, "/api/geoip", { ...init, method: "PUT", body: JSON.stringify(body) })) for (const field of ["enabled", "updateIntervalSec"] as const) if (body[field] !== undefined && body[field] !== response.status.settings[field]) throw new Error("Сохранение настроек GeoIP не подтверждено: ответ отличается от отправленных значений") return response } export async function runGeoipUpdateNow(baseUrl: string, init?: RequestInit) { return confirmed(updateSchema, await json(baseUrl, "/api/geoip/update", { ...init, method: "POST" })) }