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

export interface CurrencyInput {
  code: string;
  name: string;
  symbol?: string;
  decimals?: number;
  enabled?: boolean;
}

export interface UpdateCurrencyInput {
  name?: string;
  symbol?: string;
  decimals?: number;
  enabled?: boolean;
}

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

  list(opts?: { enabledOnly?: boolean }): Promise<Currency[]> {
    const where: Prisma.CurrencyWhereInput = {};
    if (opts?.enabledOnly !== false) where.enabled = true;
    return this.prisma.currency.findMany({ where, orderBy: { code: 'asc' } });
  }

  findByCode(code: string): Promise<Currency | null> {
    return this.prisma.currency.findUnique({ where: { code } });
  }

  async create(input: CurrencyInput, userId: string, organizationId: string) {
    const code = input.code.trim().toUpperCase();
    if (!/^[A-Z]{3}$/.test(code)) {
      throw new ConflictException({
        code: 'INVALID_CURRENCY_CODE',
        message: '货币代码必须为 3 位大写字母（ISO 4217），如 USD / CNY / EUR',
      });
    }
    const existing = await this.prisma.currency.findUnique({ where: { code } });
    if (existing) {
      throw new ConflictException({ code: 'CURRENCY_EXISTS', message: `货币 ${code} 已存在` });
    }
    return this.prisma.currency.create({
      data: {
        code,
        name: input.name,
        symbol: input.symbol,
        decimals: input.decimals ?? 2,
        enabled: input.enabled ?? true,
        organizationId,
        createdById: userId,
      },
    });
  }

  @SkipAssertAccess('findByCode 已抓到对象')
  async update(code: string, input: UpdateCurrencyInput) {
    const found = await this.findByCode(code);
    if (!found) throw new NotFoundException(`Currency ${code} not found`);
    // 拒绝空 DTO：UpdateCurrencyInput 全 optional 时，{} 会让 prisma update 跑空 SET
    // → 触发 prisma 报错或无声 no-op。要求至少一个字段
    const fieldCount = (
      [input.name, input.symbol, input.decimals, input.enabled] as Array<unknown>
    ).filter((v) => v !== undefined).length;
    if (fieldCount === 0) {
      throw new BadRequestException('Update DTO must contain at least one field');
    }
    return this.prisma.currency.update({ where: { code }, data: input });
  }

  @SkipAssertAccess('findByCode 已抓到对象')
  async setEnabled(code: string, enabled: boolean) {
    return this.update(code, { enabled });
  }
}
