import {
  ConflictException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { MESSAGES } from '../../common/messages.js';
import { PrismaService } from '../../prisma.service.js';
import {
  buildPatientLifecyclePayload,
  PATIENT_LIFECYCLE_INCLUDE,
} from '../patient-lifecycle.util.js';

const C_PATIENT_ME_INCLUDE = {
  hospital: {
    select: {
      id: true,
      name: true,
    },
  },
  doctor: {
    select: {
      id: true,
      name: true,
      role: true,
    },
  },
} as const;

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

  async getFamilyLifecycleByAccount(accountId: number) {
    const account = await this.getFamilyAccountById(accountId);
    const patient = await this.findUniqueLifecyclePatientByPhone(account.phone);

    return {
      phone: account.phone,
      ...buildPatientLifecyclePayload(patient),
    };
  }

  /**
   * 返回当前 C 端登录账号绑定的患者基础信息。
   */
  async getMeByAccount(accountId: number) {
    const account = await this.getFamilyAccountById(accountId);
    const patient = await this.findUniqueMePatientByPhone(account.phone);

    return {
      familyAccount: account,
      patient,
    };
  }

  private async getFamilyAccountById(accountId: number) {
    const account = await this.prisma.familyMiniAppAccount.findUnique({
      where: { id: accountId },
      select: {
        id: true,
        phone: true,
        openId: true,
        serviceUid: true,
        lastLoginAt: true,
      },
    });

    if (!account) {
      throw new NotFoundException(MESSAGES.AUTH.FAMILY_ACCOUNT_NOT_FOUND);
    }

    return account;
  }

  private async findUniqueLifecyclePatientByPhone(phone: string) {
    const patients = await this.prisma.patient.findMany({
      where: { phone },
      include: PATIENT_LIFECYCLE_INCLUDE,
      take: 2,
      orderBy: { id: 'asc' },
    });

    if (patients.length === 0) {
      throw new NotFoundException(MESSAGES.PATIENT.LIFE_CYCLE_NOT_FOUND);
    }
    if (patients.length > 1) {
      throw new ConflictException(
        MESSAGES.AUTH.FAMILY_PHONE_LINKED_MULTI_PATIENTS,
      );
    }

    return patients[0];
  }

  private async findUniqueMePatientByPhone(phone: string) {
    const patients = await this.prisma.patient.findMany({
      where: { phone },
      include: C_PATIENT_ME_INCLUDE,
      take: 2,
      orderBy: { id: 'asc' },
    });

    if (patients.length === 0) {
      throw new NotFoundException(
        MESSAGES.AUTH.FAMILY_PHONE_NOT_LINKED_PATIENT,
      );
    }
    if (patients.length > 1) {
      throw new ConflictException(
        MESSAGES.AUTH.FAMILY_PHONE_LINKED_MULTI_PATIENTS,
      );
    }

    const [patient] = patients;

    return {
      id: patient.id,
      name: patient.name,
      phone: patient.phone,
      idCard: patient.idCard,
      inpatientNo: patient.inpatientNo,
      projectName: patient.projectName,
      hospitalId: patient.hospitalId,
      doctorId: patient.doctorId,
      createdAt: patient.createdAt,
      hospital: patient.hospital,
      doctor: {
        id: patient.doctor.id,
        name: patient.doctor.name,
        role: patient.doctor.role,
      },
    };
  }
}
