import { Injectable, NotFoundException } from '@nestjs/common';
import type { PatientTimelineResponse } from '@pac/types';
import { FactStatus } from '@pac/types';
import { PrismaService } from '../../prisma/prisma.service';
import type { TenantScopeContext } from '../../common/decorators/tenant-scope.decorator';

/**
 * PatientService — 患者主档 + timeline
 *
 * timeline 读 patient_facts 的 active 版本(superseded / cancelled 不返回),
 * 按"时间锚点"排序:actual 用 occurredAt;planned 用 plannedFor;两者并集 desc。
 *
 * 数据来源:cold-import / pull / push 三入口 → TransactionSynthesizer 落 transactions
 *          → ParserPipeline 衍生 patient_facts(版本流)。
 */
@Injectable()
export class PatientService {
  constructor(private readonly prisma: PrismaService) {}

  /**
   * Reveal — 拉患者真实手机号(掩码 138****3405 → 13812343405)。
   *
   * 仅 PATIENT_VIEW 权限的用户可调,且强制 tenant scope 校验。
   *
   * TODO(W5+ 生产前):落 audit log(patient_pii_reveal_logs 表)
   *   记录 { userId, patientId, field='phone', revealedAt, scope:plan/timeline/manual };
   *   合规审计能反查"谁何时看了哪位患者的电话"。POC 阶段先口头记录。
   */
  async revealPhone(
    scope: TenantScopeContext,
    patientId: string,
  ): Promise<{ phone: string | null }> {
    const patient = await this.prisma.patient.findFirst({
      where: {
        id: patientId,
        hostId: scope.hostId,
        tenantId: scope.tenantId,
      },
      select: { phone: true },
    });
    if (!patient) {
      throw new NotFoundException(`patient ${patientId} not found in scope`);
    }
    return { phone: patient.phone };
  }

  async getTimeline(
    scope: TenantScopeContext,
    patientId: string,
    limit: number,
  ): Promise<PatientTimelineResponse> {
    const patient = await this.prisma.patient.findFirst({
      where: {
        id: patientId,
        hostId: scope.hostId,
        tenantId: scope.tenantId,
      },
    });
    if (!patient) {
      throw new NotFoundException(`patient ${patientId} not found in scope`);
    }

    // active 版本(每 subject_id 唯一);
    // 按时间锚点 desc 排序:actual 用 occurredAt,planned 用 plannedFor。
    const facts = await this.prisma.patientFact.findMany({
      where: {
        hostId: scope.hostId,
        tenantId: scope.tenantId,
        patientId: patient.id,
        status: FactStatus.ACTIVE,
      },
      orderBy: [
        // actual 用 occurredAt;planned 该字段空 → nulls:last 让 actual 落前
        { occurredAt: { sort: 'desc', nulls: 'last' } },
        // planned 用 plannedFor(actual 该字段空,nulls 不影响)
        { plannedFor: { sort: 'desc', nulls: 'last' } },
        { createdAt: 'desc' },
      ],
      take: limit,
    });

    return {
      patient: {
        id: patient.id,
        externalId: patient.externalId,
        name: patient.name,
        phone: patient.phone,
        gender: patient.gender,
        birthDate: patient.birthDate ? patient.birthDate.toISOString() : null,
        status: patient.active ? 'active' : 'archived',
      },
      facts: facts.map((f) => ({
        id: f.id,
        subjectId: f.subjectId,
        kind: f.kind as PatientTimelineResponse['facts'][number]['kind'],
        type: f.type,
        status: f.status as PatientTimelineResponse['facts'][number]['status'],
        version: f.version,
        clinicId: f.clinicId,
        occurredAt: f.occurredAt ? f.occurredAt.toISOString() : null,
        plannedFor: f.plannedFor ? f.plannedFor.toISOString() : null,
        validFrom: f.validFrom ? f.validFrom.toISOString() : null,
        validUntil: f.validUntil ? f.validUntil.toISOString() : null,
        title: f.title,
        summary: f.summary,
        content: f.content as Record<string, unknown>,
        transactionIds: f.transactionIds,
        createdAt: f.createdAt.toISOString(),
        updatedAt: f.updatedAt.toISOString(),
        supersededAt: f.supersededAt ? f.supersededAt.toISOString() : null,
      })),
    };
  }
}
