import { Injectable, ConflictException, ForbiddenException, NotFoundException } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { AiUsageOsPlatform, Prisma } from '@prisma/client';
import { SkipAssertAccess } from '@common/decorators/skip-assert-access.decorator';

/**
 * admin-only 路径要求 organizationId 必须存在；缺失时（itadmin 未设当前 org / 上下文丢失）
 * 不允许 silently 跨 org 返全量数据，统一抛 ForbiddenException。
 */
function requireOrg(organizationId: string | undefined | null): string {
  if (!organizationId) {
    throw new ForbiddenException('AI_USAGE_ORG_CONTEXT_REQUIRED');
  }
  return organizationId;
}

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

  async list(filter: {
    organizationId: string;
    status?: 'all' | 'active' | 'blocked';
    q?: string;
    platform?: AiUsageOsPlatform;
    skip?: number;
    take?: number;
  }) {
    const where: Prisma.AiUsageDeviceWhereInput = { organizationId: requireOrg(filter.organizationId) };
    if (filter.status === 'active') where.blockedAt = null;
    if (filter.status === 'blocked') where.blockedAt = { not: null };
    if (filter.platform) where.osPlatform = filter.platform;
    if (filter.q) {
      where.OR = [
        { hostname: { contains: filter.q, mode: 'insensitive' } },
        { deviceId: { contains: filter.q, mode: 'insensitive' } },
        { user: { email: { contains: filter.q, mode: 'insensitive' } } },
        { user: { displayName: { contains: filter.q, mode: 'insensitive' } } },
      ];
    }

    const [items, total] = await Promise.all([
      this.prisma.aiUsageDevice.findMany({
        where,
        orderBy: { lastSeenAt: 'desc' },
        skip: filter.skip ?? 0,
        take: filter.take ?? 20,
        include: { user: { select: { id: true, displayName: true, email: true } } },
      }),
      this.prisma.aiUsageDevice.count({ where }),
    ]);
    return { items, total };
  }

  @SkipAssertAccess('已在 findFirst 中按 organizationId 过滤；找不到 → NotFoundException，等价于 IDOR 防护')
  async block(params: { deviceId: string; organizationId: string; adminId: string; reason: string }) {
    const orgId = requireOrg(params.organizationId);
    const found = await this.prisma.aiUsageDevice.findFirst({
      where: { id: params.deviceId, organizationId: orgId },
    });
    if (!found) throw new NotFoundException('AI_USAGE_DEVICE_NOT_FOUND');
    if (found.blockedAt) throw new ConflictException('AI_USAGE_DEVICE_ALREADY_BLOCKED');
    return this.prisma.aiUsageDevice.update({
      where: { id: found.id },
      data: { blockedAt: new Date(), blockedById: params.adminId, blockedReason: params.reason },
    });
  }

  @SkipAssertAccess('已在 findFirst 中按 organizationId 过滤；找不到 → NotFoundException，等价于 IDOR 防护')
  async unblock(params: { deviceId: string; organizationId: string }) {
    const orgId = requireOrg(params.organizationId);
    const found = await this.prisma.aiUsageDevice.findFirst({
      where: { id: params.deviceId, organizationId: orgId },
    });
    if (!found) throw new NotFoundException('AI_USAGE_DEVICE_NOT_FOUND');
    if (!found.blockedAt) return found;
    return this.prisma.aiUsageDevice.update({
      where: { id: found.id },
      data: { blockedAt: null, blockedById: null, blockedReason: null },
    });
  }

  async listDlq(filter: { organizationId: string; reason?: string; skip?: number; take?: number }) {
    const where: any = { organizationId: requireOrg(filter.organizationId) };
    if (filter.reason) where.reason = filter.reason;
    const [items, total] = await Promise.all([
      this.prisma.aiUsageEventDlq.findMany({
        where,
        orderBy: { createdAt: 'desc' },
        skip: filter.skip ?? 0,
        take: filter.take ?? 20,
      }),
      this.prisma.aiUsageEventDlq.count({ where }),
    ]);
    return { items, total };
  }
}
