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

export interface LocationInput {
  code?: string;
  name: string;
  type: LocationType;
  countryCode?: string;
  address?: string;
  parentLocationId?: string;
  customerId?: string;
  enabled?: boolean;
}

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

  async list(query: {
    search?: string;
    type?: LocationType;
    customerId?: string;
    enabledOnly?: boolean;
  }) {
    const where: Prisma.LocationWhereInput = { deletedAt: null };
    if (query.enabledOnly) where.enabled = true;
    if (query.type) where.type = query.type;
    if (query.customerId) where.customerId = query.customerId;
    if (query.search) {
      where.OR = [
        { code: { contains: query.search, mode: 'insensitive' } },
        { name: { contains: query.search, mode: 'insensitive' } },
      ];
    }
    return this.prisma.location.findMany({ where, orderBy: { code: 'asc' } });
  }

  async findOne(id: string) {
    const l = await this.prisma.location.findFirst({
      where: { id, deletedAt: null },
      include: { parent: true, children: { take: 50 } },
    });
    if (!l) throw new NotFoundException(`Location ${id} not found`);
    return l;
  }

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

  async create(input: LocationInput, userId: string, organizationId: string) {
    const code = input.code ?? `L-${Date.now()}`;
    return this.prisma.location.create({
      data: {
        code,
        name: input.name,
        type: input.type,
        countryCode: input.countryCode,
        address: input.address,
        parentLocationId: input.parentLocationId,
        customerId: input.customerId,
        enabled: input.enabled ?? true,
        organizationId,
        createdById: userId,
      },
    });
  }

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

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

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