import { BadRequestException, Injectable, 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 CreateSkuInput {
  modelId: string;
  code?: string;
  name: string;
  variant?: string;
  defaultPrice?: number;
  defaultCost?: number;
  description?: string;
  enabled?: boolean;
  metadata?: Record<string, any>;
}

export type UpdateSkuInput = Partial<Omit<CreateSkuInput, 'code'>>;

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

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

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

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

  async create(input: CreateSkuInput, userId: string, organizationId: string) {
    const model = await this.prisma.robotModel.findFirst({
      where: { id: input.modelId, deletedAt: null },
    });
    if (!model) throw new BadRequestException(`Model ${input.modelId} not found`);
    const code = input.code?.trim() || generateEntityCode('SKU');
    try {
      return await this.prisma.robotSku.create({
        data: { ...input, code, organizationId, createdById: userId },
      });
    } catch (e: any) {
      if (e.code === 'P2002') {
        throw new BadRequestException(`SKU code ${code} already exists`);
      }
      throw e;
    }
  }

  @SkipAssertAccess('Admin 端字典型主数据 (RobotSku)，OrganizationScope=ALL 共享；按 id 更新无 IDOR 风险')
  async update(id: string, input: UpdateSkuInput) {
    await this.findOne(id);
    if (input.modelId) {
      const model = await this.prisma.robotModel.findFirst({
        where: { id: input.modelId, deletedAt: null },
      });
      if (!model) throw new BadRequestException(`Model ${input.modelId} not found`);
    }
    return this.prisma.robotSku.update({ where: { id }, data: input });
  }

  // 软删除：保留行，仅置 deletedAt + enabled=false
  @SkipAssertAccess('Admin 端字典型主数据 (RobotSku)，OrganizationScope=ALL 共享；按 id 软删除无 IDOR 风险')
  async delete(id: string) {
    const hasActiveUnits = await this.prisma.robotUnit.count({
      where: { skuId: id, deletedAt: null },
    });
    if (hasActiveUnits > 0) {
      throw new BadRequestException(
        `Cannot delete: ${hasActiveUnits} active robot unit(s) still reference this SKU. Disable it instead.`,
      );
    }
    await this.prisma.robotSku.update({
      where: { id },
      data: { deletedAt: new Date(), enabled: false },
    });
    return { success: true };
  }
}
