import { BadRequestException, Injectable, Logger, NotFoundException } from '@nestjs/common';
import { PrismaService } from '@core/database/prisma/prisma.service';
import { Prisma } from '@prisma/client';
import { SkipAssertAccess } from '@common/decorators/skip-assert-access.decorator';
import { generateEntityCode } from './entity-code.util';

export interface CreateModelInput {
  code?: string;
  name: string;
  brand?: string;
  description?: string;
  imageUrl?: string;
  enabled?: boolean;
  metadata?: Record<string, any>;
}

export type UpdateModelInput = Partial<Omit<CreateModelInput, 'code'>>;

@Injectable()
export class RobotModelService {
  private readonly logger = new Logger(RobotModelService.name);

  constructor(private readonly prisma: PrismaService) {}

  async list(query: { search?: string; enabledOnly?: boolean } = {}) {
    const where: Prisma.RobotModelWhereInput = {
      deletedAt: null,
      ...(query.enabledOnly ? { enabled: true } : {}),
      ...(query.search
        ? {
            OR: [
              { code: { contains: query.search, mode: 'insensitive' } },
              { name: { contains: query.search, mode: 'insensitive' } },
              { brand: { contains: query.search, mode: 'insensitive' } },
            ],
          }
        : {}),
    };
    return this.prisma.robotModel.findMany({
      where,
      orderBy: { code: 'asc' },
      include: {
        _count: { select: { skus: { where: { deletedAt: null } }, robotUnits: { where: { deletedAt: null } } } },
      },
    });
  }

  async findOne(id: string) {
    const row = await this.prisma.robotModel.findFirst({
      where: { id, deletedAt: null },
      include: { skus: { where: { deletedAt: null } } },
    });
    if (!row) throw new NotFoundException(`RobotModel ${id} not found`);
    return row;
  }

  /// 批量按 code 查 RobotModel；M1 import 工具 RobotUnit importer 用（14-prd §13 M0）
  /// 返回 Map<code, RobotModel>；找不到的 code 缺 key（不抛错）；过滤软删除
  async findByCodesIn(codes: string[]): Promise<Map<string, Awaited<ReturnType<typeof this.prisma.robotModel.findFirst>>>> {
    if (codes.length === 0) return new Map();
    const rows = await this.prisma.robotModel.findMany({
      where: { code: { in: codes }, deletedAt: null },
    });
    return new Map(rows.map((r) => [r.code, r]));
  }

  async create(input: CreateModelInput, userId: string, organizationId: string) {
    const code = input.code?.trim() || generateEntityCode('MDL');
    try {
      return await this.prisma.robotModel.create({
        data: { ...input, code, organizationId, createdById: userId },
      });
    } catch (e: any) {
      if (e.code === 'P2002') {
        throw new BadRequestException(`Model code ${code} already exists`);
      }
      throw e;
    }
  }

  async update(id: string, input: UpdateModelInput) {
    await this.findOne(id);
    return this.prisma.robotModel.update({ where: { id }, data: input });
  }

  // 软删除：保留行，仅置 deletedAt + enabled=false（已删行也明确停用）
  @SkipAssertAccess('Admin 端字典型主数据 (RobotModel)，OrganizationScope=ALL 共享；按 id 软删除无 IDOR 风险')
  async delete(id: string) {
    const [hasActiveUnits, hasActiveSkus] = await Promise.all([
      this.prisma.robotUnit.count({ where: { modelId: id, deletedAt: null } }),
      this.prisma.robotSku.count({ where: { modelId: id, deletedAt: null } }),
    ]);
    if (hasActiveUnits > 0) {
      throw new BadRequestException(
        `Cannot delete: ${hasActiveUnits} active robot unit(s) still reference this model. Disable it instead.`,
      );
    }
    if (hasActiveSkus > 0) {
      throw new BadRequestException(
        `Cannot delete: ${hasActiveSkus} active SKU(s) still reference this model. Delete SKUs first.`,
      );
    }
    await this.prisma.robotModel.update({
      where: { id },
      data: { deletedAt: new Date(), enabled: false },
    });
    return { success: true };
  }
}
