/**
 * AdminRPC gRPC client for Node.js environment.
 *
 * Uses raw HTTP/1.1 with the tonic gRPC server.
 * All methods pass body_json as a JSON string (matching the proto design).
 */

import { create, toBinary, fromBinary } from "@bufbuild/protobuf";
import type { IncomingMessage } from "node:http";
import { ADMIN_RPC_URL } from "@/lib/env";

// Import schemas from generated proto
import * as admin from "./generated/proto/admin_pb";

// ─── Low-level gRPC-Web over HTTP/1.1 ────────────────────────────────────────

function grpcRequest(
  baseUrl: string,
  servicePath: string,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  schema: any,
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  responseSchema: any,
  body: Uint8Array,
): Promise<Uint8Array> {
  return new Promise((resolve, reject) => {
    const url = new URL(baseUrl);
    const isHttps = url.protocol === "https:";
    // eslint-disable-next-line @typescript-eslint/no-require-imports
    const http = (isHttps ? require("node:https") : require("node:http")) as typeof import("node:http");

    const req = http.request(
      {
        hostname: url.hostname,
        port: url.port || (isHttps ? 443 : 80),
        path: servicePath,
        method: "POST",
        headers: {
          "Content-Type": "application/grpc-web+proto",
          "X-Grpc-Web": "1",
          "TE": "trailers",
          "User-Agent": "admin-module/1.0",
          "Content-Length": body.byteLength,
        },
      },
      (res: IncomingMessage) => {
        const chunks: Buffer[] = [];
        res.on("data", (chunk: Buffer) => chunks.push(chunk));
        res.on("end", () => {
          const data = Buffer.concat(chunks);
          if (data.length === 0) {
            const grpcStatus = res.headers["grpc-status"];
            if (grpcStatus && grpcStatus !== "0") {
              reject(new Error(`gRPC error ${grpcStatus}: ${res.headers["grpc-message"] || ""}`));
              return;
            }
            resolve(new Uint8Array(0));
            return;
          }
          // gRPC-web body format: [0x00, 4-byte big-endian length, payload...]
          if (data[0] === 0x00 && data.length > 5) {
            const bodyBytes = data.slice(5);
            resolve(new Uint8Array(bodyBytes.buffer, bodyBytes.byteOffset, bodyBytes.byteLength));
          } else {
            resolve(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
          }
        });
      },
    );
    req.on("error", reject);
    req.write(body);
    req.end();
  });
}

// ─── Message encoding / decoding ──────────────────────────────────────────────

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function encode(schema: any, init: Record<string, unknown>): Uint8Array {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const msg = create(schema as any, init as any);
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  return toBinary(schema as any, msg as any);
}

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function decode(schema: any, bytes: Uint8Array): any {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  return fromBinary(schema as any, bytes) as any;
}

// ─── AI: Provider CRUD ────────────────────────────────────────────────────────

export async function createProvider(body: unknown): Promise<unknown> {
  const msgBody = encode(admin.CreateProviderRequestSchema, { bodyJson: JSON.stringify(body) });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/CreateProvider",
    admin.CreateProviderRequestSchema,
    admin.ProviderResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return {};
  const resp = decode(admin.ProviderResponseSchema, bytes);
  return JSON.parse(resp.bodyJson || "{}");
}

export async function updateProvider(id: string, body: unknown): Promise<unknown> {
  const msgBody = encode(admin.UpdateProviderRequestSchema, { id, bodyJson: JSON.stringify(body) });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/UpdateProvider",
    admin.UpdateProviderRequestSchema,
    admin.ProviderResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return {};
  const resp = decode(admin.ProviderResponseSchema, bytes);
  return JSON.parse(resp.bodyJson || "{}");
}

export async function deleteProvider(id: string): Promise<{ deleted: boolean }> {
  const msgBody = encode(admin.DeleteProviderRequestSchema, { id });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/DeleteProvider",
    admin.DeleteProviderRequestSchema,
    admin.DeleteResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return { deleted: false };
  const resp = decode(admin.DeleteResponseSchema, bytes);
  return { deleted: resp.deleted };
}

// ─── AI: Model CRUD ───────────────────────────────────────────────────────────

export async function createModel(body: unknown): Promise<unknown> {
  const msgBody = encode(admin.CreateModelRequestSchema, { bodyJson: JSON.stringify(body) });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/CreateModel",
    admin.CreateModelRequestSchema,
    admin.ModelResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return {};
  const resp = decode(admin.ModelResponseSchema, bytes);
  return JSON.parse(resp.bodyJson || "{}");
}

export async function updateModel(id: string, body: unknown): Promise<unknown> {
  const msgBody = encode(admin.UpdateModelRequestSchema, { id, bodyJson: JSON.stringify(body) });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/UpdateModel",
    admin.UpdateModelRequestSchema,
    admin.ModelResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return {};
  const resp = decode(admin.ModelResponseSchema, bytes);
  return JSON.parse(resp.bodyJson || "{}");
}

export async function deleteModel(id: string): Promise<{ deleted: boolean }> {
  const msgBody = encode(admin.DeleteModelRequestSchema, { id });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/DeleteModel",
    admin.DeleteModelRequestSchema,
    admin.DeleteResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return { deleted: false };
  const resp = decode(admin.DeleteResponseSchema, bytes);
  return { deleted: resp.deleted };
}

// ─── AI: Version CRUD ─────────────────────────────────────────────────────────

export async function createVersion(body: unknown): Promise<unknown> {
  const msgBody = encode(admin.CreateVersionRequestSchema, { bodyJson: JSON.stringify(body) });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/CreateVersion",
    admin.CreateVersionRequestSchema,
    admin.VersionResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return {};
  const resp = decode(admin.VersionResponseSchema, bytes);
  return JSON.parse(resp.bodyJson || "{}");
}

export async function updateVersion(id: string, body: unknown): Promise<unknown> {
  const msgBody = encode(admin.UpdateVersionRequestSchema, { id, bodyJson: JSON.stringify(body) });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/UpdateVersion",
    admin.UpdateVersionRequestSchema,
    admin.VersionResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return {};
  const resp = decode(admin.VersionResponseSchema, bytes);
  return JSON.parse(resp.bodyJson || "{}");
}

export async function deleteVersion(id: string): Promise<{ deleted: boolean }> {
  const msgBody = encode(admin.DeleteVersionRequestSchema, { id });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/DeleteVersion",
    admin.DeleteVersionRequestSchema,
    admin.DeleteResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return { deleted: false };
  const resp = decode(admin.DeleteResponseSchema, bytes);
  return { deleted: resp.deleted };
}

// ─── AI: Pricing Update ───────────────────────────────────────────────────────

export async function updatePricing(id: string, body: unknown): Promise<unknown> {
  const msgBody = encode(admin.UpdatePricingRequestSchema, { id, bodyJson: JSON.stringify(body) });
  const bytes = await grpcRequest(
    ADMIN_RPC_URL,
    "/admin.SessionAdmin/UpdatePricing",
    admin.UpdatePricingRequestSchema,
    admin.PricingResponseSchema,
    msgBody,
  );
  if (bytes.length === 0) return {};
  const resp = decode(admin.PricingResponseSchema, bytes);
  return JSON.parse(resp.bodyJson || "{}");
}
