import { eq, and } from "drizzle-orm";
import db from "../../db";
import { servers } from "../../db/schema/servers";

export type ServerType = "stream" | "local";
export type ServerLocation = "ru1" | "uae1";
export type ServerTier = "demo" | "prod";

export interface CreateServerParams {
  localIp: string;
  hostname: string;
  type: ServerType;
  gpuFreeMb: number;
  branchId?: string;
  location?: ServerLocation;
  tier?: ServerTier;
}

export interface UpdateServerParams {
  localIp?: string;
  hostname?: string;
  gpuFreeMb?: number;
  branchId?: string;
  location?: ServerLocation;
  tier?: ServerTier;
}

export interface FindServersFilters {
  type?: ServerType;
  location?: ServerLocation;
  tier?: ServerTier;
  branchId?: string;
}

/**
 * Сервис для работы с серверами
 */
export const serverService = {
  /**
   * Создать сервер
   */
  async create(params: CreateServerParams) {
    // Валидация для stream-серверов
    if (params.type === "stream" && !params.location) {
      throw new Error("Location is required for stream servers");
    }

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

    const [server] = await db
      .insert(servers)
      .values({
        localIp: params.localIp,
        hostname: params.hostname,
        type: params.type,
        gpuFreeMb: params.gpuFreeMb,
        branchId: params.branchId,
        location: params.location,
        tier: tier,
      })
      .returning();

    return server;
  },

  /**
   * Получить все серверы с фильтрацией
   */
  async findAll(filters?: FindServersFilters) {
    const conditions = [];

    if (filters?.type) {
      conditions.push(eq(servers.type, filters.type));
    }

    if (filters?.location) {
      conditions.push(eq(servers.location, filters.location));
    }

    if (filters?.tier) {
      conditions.push(eq(servers.tier, filters.tier));
    }

    if (filters?.branchId) {
      conditions.push(eq(servers.branchId, filters.branchId));
    }

    const allServers = await db.query.servers.findMany({
      where: conditions.length > 0 ? and(...conditions) : undefined,
      orderBy: (servers, { asc }) => [asc(servers.hostname)],
    });

    return allServers;
  },

  /**
   * Найти сервер по ID
   */
  async findById(serverId: string) {
    const server = await db.query.servers.findFirst({
      where: eq(servers.id, serverId),
    });

    return server || null;
  },

  /**
   * Найти сервер по hostname
   */
  async findByHostname(hostname: string) {
    const server = await db.query.servers.findFirst({
      where: eq(servers.hostname, hostname),
    });

    return server || null;
  },

  /**
   * Получить серверы по филиалу
   */
  async findByBranchId(branchId: string) {
    const branchServers = await db.query.servers.findMany({
      where: eq(servers.branchId, branchId),
      orderBy: (servers, { asc }) => [asc(servers.hostname)],
    });

    return branchServers;
  },

  /**
   * Получить доступные stream-серверы
   */
  async findAvailableStreamServers(tier?: ServerTier) {
    const conditions = [eq(servers.type, "stream")];

    if (tier) {
      conditions.push(eq(servers.tier, tier));
    }

    const streamServers = await db.query.servers.findMany({
      where: and(...conditions),
      orderBy: (servers, { desc }) => [desc(servers.gpuFreeMb)],
    });

    return streamServers;
  },

  /**
   * Получить доступные local-серверы
   */
  async findAvailableLocalServers(branchId?: string) {
    const conditions = [eq(servers.type, "local")];

    if (branchId) {
      conditions.push(eq(servers.branchId, branchId));
    }

    const localServers = await db.query.servers.findMany({
      where: and(...conditions),
      orderBy: (servers, { desc }) => [desc(servers.gpuFreeMb)],
    });

    return localServers;
  },

  /**
   * Обновить сервер
   */
  async update(serverId: string, params: UpdateServerParams) {
    const updateData: any = {
      updatedAt: new Date(),
    };

    if (params.localIp) {
      updateData.localIp = params.localIp;
    }

    if (params.hostname) {
      updateData.hostname = params.hostname;
    }

    if (params.gpuFreeMb !== undefined) {
      updateData.gpuFreeMb = params.gpuFreeMb;
    }

    if (params.branchId !== undefined) {
      updateData.branchId = params.branchId;
    }

    if (params.location !== undefined) {
      updateData.location = params.location;
    }

    if (params.tier !== undefined) {
      updateData.tier = params.tier;
    }

    const [updatedServer] = await db
      .update(servers)
      .set(updateData)
      .where(eq(servers.id, serverId))
      .returning();

    return updatedServer;
  },

  /**
   * Обновить свободную память GPU
   */
  async updateGpuMemory(serverId: string, gpuFreeMb: number) {
    const [updatedServer] = await db
      .update(servers)
      .set({
        gpuFreeMb,
        updatedAt: new Date(),
      })
      .where(eq(servers.id, serverId))
      .returning();

    return updatedServer;
  },

  /**
   * Удалить сервер
   */
  async delete(serverId: string) {
    await db.delete(servers).where(eq(servers.id, serverId));
  },
};

