import { Injectable, Logger } from '@nestjs/common';
import { Action, FactKind, FactStatus, FactType } from '@pac/types';
import type { FactDraft, Parser, ParserContext } from './parser.interface';

/**
 * PaymentParser — `payment_received` 解析器
 *
 * 一条 payment transaction 衍生:
 *   - 1 个 `payment_record`(actual)— 收款事实
 *     subject_id = `payment_record:{externalId}`
 *     content.amount = cents int(FieldMapper.normalize 已转换)
 *     content.order_external_id 关联医嘱(可选)
 *
 * 副作用(应用层处理,不在 parser 做):
 *   - 关联的 charge_order_record / payment_plan 状态机:
 *     比对 sum(payments.amount) vs charge_order.total_amount:
 *       全付 → charge_order_record status=fulfilled,payment_plan supersede 走人
 *       部分 → charge_order_record status=active(host 侧通常会用 partial_paid 推一条 update)
 *     这层依赖跨 fact 的聚合,由 W3 PersonaService / PlanService 在 read path 算,
 *     不在 parser 写入侧做(避免 fact 之间紧耦合)。
 *
 * Persona `value` 累计消费用 payment_record.amount 求和(扣 refund_record)。
 */
@Injectable()
export class PaymentParser implements Parser {
  readonly name = Action.PAYMENT_RECEIVED;
  private readonly logger = new Logger(PaymentParser.name);

  parse(ctx: ParserContext): FactDraft[] {
    const c = ctx.canonicalRow;
    const externalId = String(c.externalId ?? ctx.transaction.subjectId).trim();
    if (!externalId) {
      this.logger.warn(
        `payment parser: missing externalId for transaction=${ctx.transaction.id};skip`,
      );
      return [];
    }

    const amount = Number(c.amount ?? 0); // cents(实付;2026-07 业务定调,应收在 receivableAmount)
    // 应收(原价,可空)— 折扣率分母 / 权益客识别(实付0+应收>0=纯权益客)
    const receivableRaw = Number(c.receivableAmount ?? NaN);
    const receivable = Number.isFinite(receivableRaw) ? Math.round(receivableRaw) : null;
    const paidAt = c.paidAt ? new Date(c.paidAt as string) : null;
    const encounterExternalId =
      (c.encounterExternalId as string | undefined) ?? null;
    const orderExternalId = (c.orderExternalId as string | undefined) ?? null;
    const method = (c.method as string | undefined) ?? null;
    const doctorId = c.doctorId ? String(c.doctorId) : null; // host Int64,0/null → null
    const currency = (c.currency as string | undefined) ?? 'CNY';
    // 商保公司名(可空):非空 = 商保结算;喂 persona「权益身份」。归一在 feature 层做。
    const insRaw = (c.insuranceName as string | undefined) ?? null;
    const insuranceName = insRaw && insRaw.trim() ? insRaw.trim() : null;
    // 卡券名称(B.1.3 权益身份):card_type_name / card_name;关键词匹配在 feature 层做。
    // String() 强转 — host 偶有数字型卡券值(.trim 直接调会炸)。
    const cardTypeName = String(c.cardTypeName ?? '').trim() || null;
    const cardName = String(c.cardName ?? '').trim() || null;
    // 折扣锚点(D.1.3):诊所可控折扣额;折扣率 = 1 - 折扣/应收(feature 算)。
    // 单位归一交给 normalizer(三字段已登记 payment.moneyFields,按 amountUnit 转分),这里只求和。
    // ⚠️ 排除 discount_insurance_rate(保险方付款,非诊所价格折扣;不进"价格底线"锚点)。
    const discSum =
      Number(c.discountDept ?? 0) +
      Number(c.discountCompany ?? 0) +
      Number(c.discountCard ?? 0);
    const discountCents = Number.isFinite(discSum) ? Math.round(discSum) : 0;
    const settlementProject = String(c.settlementProject ?? '').trim() || null;

    return [
      {
        subjectId: `${FactType.PAYMENT_RECORD}:${externalId}`,
        kind: FactKind.ACTUAL,
        type: FactType.PAYMENT_RECORD,
        status: FactStatus.ACTIVE,
        clinicId: ctx.transaction.clinicId,
        occurredAt: paidAt,
        title: `收款 ¥${(amount / 100).toFixed(2)}${method ? '(' + method + ')' : ''}`,
        summary: orderExternalId ? `关联医嘱:${orderExternalId}` : null,
        content: {
          payment_external_id: externalId,
          amount_cents: amount,
          receivable_cents: receivable,
          channel: method,
          insurance_name: insuranceName,
          card_type_name: cardTypeName,
          card_name: cardName,
          discount_cents: discountCents,
          settlement_project: settlementProject,
          doctor_id: doctorId,
          encounter_external_id: encounterExternalId,
          related_order_external_id: orderExternalId,
        },
      },
    ];
  }
}
