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

export interface CustomerInput {
  code?: string;
  name: string;
  type?: CustomerType;
  industry?: string;
  countryCode?: string;
  taxId?: string;
  creditLimit?: number;
  currencyCode?: string;
  enabled?: boolean;
}

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

  async list(query: { search?: string; type?: CustomerType; enabledOnly?: boolean }) {
    const where: Prisma.CustomerWhereInput = { 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.customer.findMany({
      where,
      orderBy: { code: 'asc' },
      include: { _count: { select: { contacts: true, addresses: true } } },
    });
  }

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

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

  async create(input: CustomerInput, userId: string, organizationId: string) {
    const code = input.code ?? `C-${Date.now()}`;
    return this.prisma.customer.create({
      data: {
        code,
        name: input.name,
        type: input.type ?? CustomerType.B2B,
        industry: input.industry,
        countryCode: input.countryCode,
        taxId: input.taxId,
        creditLimit: input.creditLimit,
        currencyCode: input.currencyCode,
        enabled: input.enabled ?? true,
        organizationId,
        createdById: userId,
      },
    });
  }

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

  @SkipAssertAccess('updateMany 用 id + deletedAt:null 过滤已抓到对象；count===0 即 not found')
  async softDelete(id: string) {
    const r = await this.prisma.customer.updateMany({
      where: { id, deletedAt: null },
      data: { deletedAt: new Date() },
    });
    if (r.count === 0) throw new NotFoundException(`Customer ${id} not found`);
    return { id, deleted: true };
  }

  @SkipAssertAccess('updateMany 用 id 过滤已抓到对象；count===0 即 not found')
  async restore(id: string) {
    const r = await this.prisma.customer.updateMany({
      where: { id, deletedAt: { not: null } },
      data: { deletedAt: null },
    });
    if (r.count === 0) throw new NotFoundException(`Customer ${id} not found or not deleted`);
    return this.findOne(id);
  }
}
