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

export interface CreateAgentRepoInput {
  name: string;
  description?: string;
  systemPrompt?: string;
  llmId: string;
  projectId?: string | null;
  proxyModelName?: string | null;
  defaultParams?: Record<string, unknown>;
  extras?: Record<string, unknown>;
  ownerId: string;
}

export interface UpdateAgentRepoInput {
  description?: string;
  systemPrompt?: string;
  llmId?: string;
  projectId?: string | null;
  proxyModelName?: string | null;
  defaultParams?: Record<string, unknown>;
  extras?: Record<string, unknown>;
}

export interface IAgentRepository {
  findAll(): Promise<Agent[]>;
  findById(id: string): Promise<Agent | null>;
  findByName(name: string): Promise<Agent | null>;
  findByProjectId(projectId: string): Promise<Agent[]>;
  create(data: CreateAgentRepoInput): Promise<Agent>;
  update(id: string, data: UpdateAgentRepoInput): Promise<Agent>;
  delete(id: string): Promise<void>;
}

export class AgentRepository implements IAgentRepository {
  constructor(private readonly prisma: PrismaClient) {}

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

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

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

  async findByProjectId(projectId: string): Promise<Agent[]> {
    return this.prisma.agent.findMany({
      where: { projectId },
      orderBy: { name: 'asc' },
    });
  }

  async create(data: CreateAgentRepoInput): Promise<Agent> {
    return this.prisma.agent.create({
      data: {
        name: data.name,
        description: data.description ?? '',
        systemPrompt: data.systemPrompt ?? '',
        llmId: data.llmId,
        projectId: data.projectId ?? null,
        proxyModelName: data.proxyModelName ?? null,
        defaultParams: (data.defaultParams ?? {}) as Prisma.InputJsonValue,
        extras: (data.extras ?? {}) as Prisma.InputJsonValue,
        ownerId: data.ownerId,
      },
    });
  }

  async update(id: string, data: UpdateAgentRepoInput): Promise<Agent> {
    const updateData: Prisma.AgentUpdateInput = {};
    if (data.description !== undefined) updateData.description = data.description;
    if (data.systemPrompt !== undefined) updateData.systemPrompt = data.systemPrompt;
    if (data.llmId !== undefined) {
      updateData.llm = { connect: { id: data.llmId } };
    }
    if (data.projectId !== undefined) {
      updateData.project = data.projectId === null
        ? { disconnect: true }
        : { connect: { id: data.projectId } };
    }
    if (data.proxyModelName !== undefined) {
      updateData.proxyModelName = data.proxyModelName;
    }
    if (data.defaultParams !== undefined) {
      updateData.defaultParams = data.defaultParams as Prisma.InputJsonValue;
    }
    if (data.extras !== undefined) {
      updateData.extras = data.extras as Prisma.InputJsonValue;
    }
    // Bump optimistic version on every update.
    updateData.version = { increment: 1 };
    return this.prisma.agent.update({ where: { id }, data: updateData });
  }

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