import {
  Injectable,
  NotFoundException,
  ConflictException,
  ForbiddenException,
} from "@nestjs/common";
import { PrismaService } from "../prisma/prisma.service";
import { CreateUserAgentDto } from "./dto/create-user-agent.dto";
import { UpdateUserAgentDto } from "./dto/update-user-agent.dto";

export interface AgentStatusResponse {
  id: string;
  name: string;
  displayName: string;
  role: string;
  isActive: boolean;
  containerStatus?: "running" | "stopped" | "unknown";
}

@Injectable()
export class UserAgentService {
  constructor(private readonly prisma: PrismaService) {}

  async findAll(userId: string) {
    return this.prisma.userAgent.findMany({
      where: { userId },
      orderBy: { createdAt: "asc" },
    });
  }

  async findOne(userId: string, id: string) {
    const agent = await this.prisma.userAgent.findUnique({ where: { id } });
    if (!agent) throw new NotFoundException(`UserAgent ${id} not found`);
    if (agent.userId !== userId) throw new ForbiddenException("Access denied to this agent");
    return agent;
  }

  async findByName(userId: string, name: string) {
    const agent = await this.prisma.userAgent.findUnique({
      where: { userId_name: { userId, name } },
    });
    if (!agent) throw new NotFoundException(`UserAgent "${name}" not found for user`);
    return agent;
  }

  async create(userId: string, dto: CreateUserAgentDto) {
    // Check for unique name within user scope
    const existing = await this.prisma.userAgent.findUnique({
      where: { userId_name: { userId, name: dto.name } },
    });
    if (existing)
      throw new ConflictException(`UserAgent "${dto.name}" already exists for this user`);

    // If templateId provided, verify it exists
    if (dto.templateId) {
      const template = await this.prisma.agentTemplate.findUnique({
        where: { id: dto.templateId },
      });
      if (!template) throw new NotFoundException(`AgentTemplate ${dto.templateId} not found`);
    }

    return this.prisma.userAgent.create({
      data: {
        userId,
        templateId: dto.templateId ?? null,
        name: dto.name,
        displayName: dto.displayName,
        role: dto.role,
        personality: dto.personality,
        primaryModel: dto.primaryModel ?? null,
        fallbackModels: dto.fallbackModels ?? ([] as string[]),
        toolPermissions: dto.toolPermissions ?? ([] as string[]),
        discordChannel: dto.discordChannel ?? null,
        isActive: dto.isActive ?? true,
      },
    });
  }

  async createFromTemplate(userId: string, templateId: string) {
    const template = await this.prisma.agentTemplate.findUnique({
      where: { id: templateId },
    });
    if (!template) throw new NotFoundException(`AgentTemplate ${templateId} not found`);

    // Check for unique name within user scope
    const existing = await this.prisma.userAgent.findUnique({
      where: { userId_name: { userId, name: template.name } },
    });
    if (existing)
      throw new ConflictException(`UserAgent "${template.name}" already exists for this user`);

    return this.prisma.userAgent.create({
      data: {
        userId,
        templateId: template.id,
        name: template.name,
        displayName: template.displayName,
        role: template.role,
        personality: template.personality,
        primaryModel: template.primaryModel,
        fallbackModels: template.fallbackModels as string[],
        toolPermissions: template.toolPermissions as string[],
        discordChannel: template.discordChannel,
        isActive: template.isActive,
      },
    });
  }

  async update(userId: string, id: string, dto: UpdateUserAgentDto) {
    const agent = await this.findOne(userId, id);

    // If name is being changed, check for uniqueness
    if (dto.name && dto.name !== agent.name) {
      const existing = await this.prisma.userAgent.findUnique({
        where: { userId_name: { userId, name: dto.name } },
      });
      if (existing)
        throw new ConflictException(`UserAgent "${dto.name}" already exists for this user`);
    }

    return this.prisma.userAgent.update({
      where: { id },
      data: dto,
    });
  }

  async remove(userId: string, id: string) {
    await this.findOne(userId, id);
    return this.prisma.userAgent.delete({ where: { id } });
  }

  async getStatus(userId: string, id: string): Promise<AgentStatusResponse> {
    const agent = await this.findOne(userId, id);
    return {
      id: agent.id,
      name: agent.name,
      displayName: agent.displayName,
      role: agent.role,
      isActive: agent.isActive,
    };
  }

  async getAllStatuses(userId: string): Promise<AgentStatusResponse[]> {
    const agents = await this.findAll(userId);
    return agents.map((agent) => ({
      id: agent.id,
      name: agent.name,
      displayName: agent.displayName,
      role: agent.role,
      isActive: agent.isActive,
    }));
  }
}
