import { Elysia, t } from "elysia";
import { authMiddleware } from "../middlewares/auth";
import { serverService } from "../services/server";

export const serverController = new Elysia({ prefix: "/servers" })
  // POST /servers/register - публичный endpoint для регистрации сервера (без авторизации)
  .post(
    "/register",
    async ({ body, set }) => {
      const { localIp, hostname, type, gpuFreeMb, branchId, location, tier } =
        body as {
          localIp: string;
          hostname: string;
          type: "stream" | "local";
          gpuFreeMb: number;
          branchId?: string;
          location?: "ru1" | "uae1";
          tier?: "demo" | "prod";
        };

      // Валидация для stream-серверов
      if (type === "stream") {
        if (!location) {
          set.status = 400;
          return { error: "Location is required for stream servers" };
        }
      }

      // Валидация для local-серверов
      if (type === "local") {
        if (!branchId) {
          set.status = 400;
          return { error: "Branch ID is required for local servers" };
        }
      }

      // Установить tier по умолчанию для stream-серверов
      const finalTier = type === "stream" && !tier ? "demo" : tier;

      // Проверить, существует ли сервер с таким hostname
      const existingServer = await serverService.findByHostname(hostname);

      if (existingServer) {
        // Если сервер существует, обновить его информацию
        const updatedServer = await serverService.update(existingServer.id, {
          localIp,
          gpuFreeMb,
          branchId,
          location,
          tier: finalTier,
        });

        return { server: updatedServer, registered: false };
      }

      // Создать новый сервер
      const server = await serverService.create({
        localIp,
        hostname,
        type,
        gpuFreeMb,
        branchId,
        location,
        tier: finalTier,
      });

      return { server, registered: true };
    },
    {
      body: t.Object({
        localIp: t.String({ minLength: 7, maxLength: 45 }),
        hostname: t.String({ minLength: 1, maxLength: 255 }),
        type: t.Union([t.Literal("stream"), t.Literal("local")]),
        gpuFreeMb: t.Number({ minimum: 0 }),
        branchId: t.Optional(t.String({ format: "uuid" })),
        location: t.Optional(t.Union([t.Literal("ru1"), t.Literal("uae1")])),
        tier: t.Optional(t.Union([t.Literal("demo"), t.Literal("prod")])),
      }),
    }
  )
  // PATCH /servers/:id/gpu - обновить свободную память GPU (публичный endpoint)
  .patch(
    "/:id/gpu",
    async ({ params, body, status }) => {
      const { id } = params;
      const { gpuFreeMb } = body as { gpuFreeMb: number };

      // Проверить существование сервера
      const server = await serverService.findById(id);

      if (!server) {
        return status(404, "Server not found");
      }

      const updatedServer = await serverService.updateGpuMemory(id, gpuFreeMb);

      return { server: updatedServer };
    },
    {
      body: t.Object({
        gpuFreeMb: t.Number({ minimum: 0 }),
      }),
    }
  )
  // GET /servers/:id/sessions - получить сессии для конкретного сервера (публичный endpoint)
  .get("/:id/sessions", async ({ params, query, status }) => {
    const { id } = params;
    const { statusFilter, mode } = query as {
      statusFilter?: "starting" | "started" | "ending" | "ended";
      mode?: "stream" | "local";
    };

    // Проверить существование сервера
    const server = await serverService.findById(id);

    if (!server) {
      return status(404, "Server not found");
    }

    const { serverSessionService } = await import("../services/serverSession");
    
    // Получаем только сессии, назначенные этому серверу
    // Main server автоматически назначает серверы для unassigned сессий
    const sessions = await serverSessionService.findByServerId(id, {
      status: statusFilter,
      mode,
    });

    return { sessions };
  })
  // Все остальные роуты требуют авторизации
  .use(authMiddleware)
  // GET /servers - получить список серверов с фильтрацией
  .get("/", async ({ query }) => {
    const { type, location, tier, branchId } = query as {
      type?: "stream" | "local";
      location?: "ru1" | "uae1";
      tier?: "demo" | "prod";
      branchId?: string;
    };

    const servers = await serverService.findAll({
      type,
      location,
      tier,
      branchId,
    });

    return { servers };
  })
  // GET /servers/available/stream - получить доступные stream-серверы
  .get("/available/stream", async ({ query }) => {
    const { tier } = query as { tier?: "demo" | "prod" };

    const servers = await serverService.findAvailableStreamServers(tier);

    return { servers };
  })
  // GET /servers/available/local - получить доступные local-серверы
  .get("/available/local", async ({ query }) => {
    const { branchId } = query as { branchId?: string };

    const servers = await serverService.findAvailableLocalServers(branchId);

    return { servers };
  })
  // GET /servers/:id - получить сервер по ID
  .get("/:id", async ({ params, status }) => {
    const { id } = params;

    const server = await serverService.findById(id);

    if (!server) {
      return status(404, "Server not found");
    }

    return { server };
  })
  // POST /servers - создать сервер
  .post(
    "/",
    async ({ body, set }) => {
      const { localIp, hostname, type, gpuFreeMb, branchId, location, tier } =
        body as {
          localIp: string;
          hostname: string;
          type: "stream" | "local";
          gpuFreeMb: number;
          branchId?: string;
          location?: "ru1" | "uae1";
          tier?: "demo" | "prod";
        };

      // Валидация для stream-серверов
      if (type === "stream") {
        if (!location) {
          set.status = 400;
          return { error: "Location is required for stream servers" };
        }
      }

      // Валидация для local-серверов
      if (type === "local") {
        if (!branchId) {
          set.status = 400;
          return { error: "Branch ID is required for local servers" };
        }
      }

      // Установить tier по умолчанию для stream-серверов
      const finalTier = type === "stream" && !tier ? "demo" : tier;

      const server = await serverService.create({
        localIp,
        hostname,
        type,
        gpuFreeMb,
        branchId,
        location,
        tier: finalTier,
      });

      return { server };
    },
    {
      body: t.Object({
        localIp: t.String({ minLength: 7, maxLength: 45 }),
        hostname: t.String({ minLength: 1, maxLength: 255 }),
        type: t.Union([t.Literal("stream"), t.Literal("local")]),
        gpuFreeMb: t.Number({ minimum: 0 }),
        branchId: t.Optional(t.String({ format: "uuid" })),
        location: t.Optional(t.Union([t.Literal("ru1"), t.Literal("uae1")])),
        tier: t.Optional(t.Union([t.Literal("demo"), t.Literal("prod")])),
      }),
    }
  )
  // PATCH /servers/:id - обновить сервер
  .patch(
    "/:id",
    async ({ params, body, status, set }) => {
      const { id } = params;
      const { localIp, hostname, gpuFreeMb, branchId, location, tier } =
        body as {
          localIp?: string;
          hostname?: string;
          gpuFreeMb?: number;
          branchId?: string;
          location?: "ru1" | "uae1";
          tier?: "demo" | "prod";
        };

      // Проверить существование сервера
      const server = await serverService.findById(id);

      if (!server) {
        return status(404, "Server not found");
      }

      // Валидация для stream-серверов: нельзя удалить location
      if (server.type === "stream") {
        if (location === undefined && server.location === null) {
          set.status = 400;
          return { error: "Location cannot be removed from stream servers" };
        }
      }

      // Валидация для local-серверов: нельзя удалить branchId
      if (server.type === "local") {
        if (branchId === undefined && server.branchId === null) {
          set.status = 400;
          return { error: "Branch ID cannot be removed from local servers" };
        }
      }

      const updatedServer = await serverService.update(id, {
        localIp,
        hostname,
        gpuFreeMb,
        branchId,
        location,
        tier,
      });

      return { server: updatedServer };
    },
    {
      body: t.Object({
        localIp: t.Optional(t.String({ minLength: 7, maxLength: 45 })),
        hostname: t.Optional(t.String({ minLength: 1, maxLength: 255 })),
        gpuFreeMb: t.Optional(t.Number({ minimum: 0 })),
        branchId: t.Optional(t.String({ format: "uuid" })),
        location: t.Optional(t.Union([t.Literal("ru1"), t.Literal("uae1")])),
        tier: t.Optional(t.Union([t.Literal("demo"), t.Literal("prod")])),
      }),
    }
  )
  // DELETE /servers/:id - удалить сервер
  .delete("/:id", async ({ params, status }) => {
    const { id } = params;

    // Проверить существование сервера
    const server = await serverService.findById(id);

    if (!server) {
      return status(404, "Server not found");
    }

    await serverService.delete(id);

    return { message: "Server deleted successfully" };
  });
