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

export interface SupplierInput {
  code?: string;
  name: string;
  type?: SupplierType;
  countryCode?: string;
  currencyCode?: string;
  paymentTerms?: string;
  leadTimeDays?: number;
  enabled?: boolean;
}

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

  async list(query: { search?: string; type?: SupplierType; enabledOnly?: boolean }) {
    const where: Prisma.SupplierWhereInput = { deletedAt: null };
    if (query.enabledOnly) where.enabled = true;
    if (query.type) where.type = query.type;
    if (query.search) {
      where.OR = [
        { code: { contains: query.search, mode: 'insensitive' } },
        { name: { contains: query.search, mode: 'insensitive' } },
      ];
    }
    return this.prisma.supplier.findMany({
      where,
      orderBy: { code: 'asc' },
      include: { _count: { select: { contacts: true } } },
    });
  }

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

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

  async create(input: SupplierInput, userId: string, organizationId: string) {
    const code = input.code ?? `S-${Date.now()}`;
    return this.prisma.supplier.create({
      data: {
        code,
        name: input.name,
        type: input.type ?? SupplierType.MANUFACTURER,
        countryCode: input.countryCode,
        currencyCode: input.currencyCode,
        paymentTerms: input.paymentTerms,
        leadTimeDays: input.leadTimeDays,
        enabled: input.enabled ?? true,
        organizationId,
        createdById: userId,
      },
    });
  }

  @SkipAssertAccess('上方 findOne({ id }) 已抓到对象')
  async update(id: string, input: Partial<SupplierInput>) {
    await this.findOne(id);
    return this.prisma.supplier.update({ where: { id }, data: input });
  }

  @SkipAssertAccess('updateMany 单 round-trip 删除 + 已抓到对象判定')
  async softDelete(id: string) {
    const r = await this.prisma.supplier.updateMany({
      where: { id, deletedAt: null },
      data: { deletedAt: new Date() },
    });
    if (r.count === 0) throw new NotFoundException(`Supplier ${id} not found`);
    return { id, deleted: true };
  }

  @SkipAssertAccess('updateMany 单 round-trip')
  async restore(id: string) {
    const r = await this.prisma.supplier.updateMany({
      where: { id, deletedAt: { not: null } },
      data: { deletedAt: null },
    });
    if (r.count === 0) throw new NotFoundException(`Supplier ${id} not found or not deleted`);
    return this.findOne(id);
  }
}
