import type { PrismaClient, Llm, Prisma } from '@prisma/client';

export interface CreateLlmInput {
  name: string;
  type: string;
  model: string;
  url?: string;
  tier?: string;
  description?: string;
  apiKeySecretId?: string | null;
  apiKeySecretKey?: string | null;
  extraConfig?: Record<string, unknown>;
}

export interface UpdateLlmInput {
  model?: string;
  url?: string;
  tier?: string;
  description?: string;
  apiKeySecretId?: string | null;
  apiKeySecretKey?: string | null;
  extraConfig?: Record<string, unknown>;
}

export interface ILlmRepository {
  findAll(): Promise<Llm[]>;
  findById(id: string): Promise<Llm | null>;
  findByName(name: string): Promise<Llm | null>;
  findByTier(tier: string): Promise<Llm[]>;
  create(data: CreateLlmInput): Promise<Llm>;
  update(id: string, data: UpdateLlmInput): Promise<Llm>;
  delete(id: string): Promise<void>;
}

export class LlmRepository implements ILlmRepository {
  constructor(private readonly prisma: PrismaClient) {}

  async findAll(): Promise<Llm[]> {
    return this.prisma.llm.findMany({ orderBy: { name: 'asc' } });
  }

  async findById(id: string): Promise<Llm | null> {
    return this.prisma.llm.findUnique({ where: { id } });
  }

  async findByName(name: string): Promise<Llm | null> {
    return this.prisma.llm.findUnique({ where: { name } });
  }

  async findByTier(tier: string): Promise<Llm[]> {
    return this.prisma.llm.findMany({ where: { tier }, orderBy: { name: 'asc' } });
  }

  async create(data: CreateLlmInput): Promise<Llm> {
    return this.prisma.llm.create({
      data: {
        name: data.name,
        type: data.type,
        model: data.model,
        url: data.url ?? '',
        tier: data.tier ?? 'fast',
        description: data.description ?? '',
        apiKeySecretId: data.apiKeySecretId ?? null,
        apiKeySecretKey: data.apiKeySecretKey ?? null,
        extraConfig: (data.extraConfig ?? {}) as Prisma.InputJsonValue,
      },
    });
  }

  async update(id: string, data: UpdateLlmInput): Promise<Llm> {
    const updateData: Prisma.LlmUpdateInput = {};
    if (data.model !== undefined) updateData.model = data.model;
    if (data.url !== undefined) updateData.url = data.url;
    if (data.tier !== undefined) updateData.tier = data.tier;
    if (data.description !== undefined) updateData.description = data.description;
    if (data.apiKeySecretId !== undefined) {
      updateData.apiKeySecret = data.apiKeySecretId === null
        ? { disconnect: true }
        : { connect: { id: data.apiKeySecretId } };
    }
    if (data.apiKeySecretKey !== undefined) updateData.apiKeySecretKey = data.apiKeySecretKey;
    if (data.extraConfig !== undefined) updateData.extraConfig = data.extraConfig as Prisma.InputJsonValue;
    return this.prisma.llm.update({ where: { id }, data: updateData });
  }

  async delete(id: string): Promise<void> {
    await this.prisma.llm.delete({ where: { id } });
  }
}
