import { Prisma } from '../generated/prisma/client.js';

const IMPLANT_CATALOG_SELECT = {
  id: true,
  modelCode: true,
  manufacturer: true,
  name: true,
  isValve: true,
  pressureLevels: true,
  isPressureAdjustable: true,
  notes: true,
} as const;

export const PATIENT_LIFECYCLE_INCLUDE = {
  hospital: { select: { id: true, name: true } },
  doctor: { select: { departmentId: true, groupId: true } },
  surgeries: {
    include: {
      devices: {
        include: {
          implantCatalog: {
            select: IMPLANT_CATALOG_SELECT,
          },
        },
      },
    },
    orderBy: { surgeryDate: 'desc' },
  },
  devices: {
    include: {
      surgery: {
        select: {
          id: true,
          surgeryDate: true,
          surgeryName: true,
        },
      },
      implantCatalog: {
        select: IMPLANT_CATALOG_SELECT,
      },
      taskItems: {
        include: {
          task: true,
        },
      },
    },
  },
} as const satisfies Prisma.PatientInclude;

export type PatientLifecycleSource = Prisma.PatientGetPayload<{
  include: typeof PATIENT_LIFECYCLE_INCLUDE;
}>;

export function buildPatientLifecyclePayload(patient: PatientLifecycleSource) {
  return {
    patient: buildPatientLifecyclePatient(patient),
    lifecycle: buildPatientLifecycleEvents(patient),
  };
}

export function buildPatientLifecyclePatient(patient: PatientLifecycleSource) {
  return {
    id: toJsonNumber(patient.id),
    name: patient.name,
    inpatientNo: patient.inpatientNo,
    projectName: patient.projectName,
  };
}

export function buildPatientLifecycleEvents(patient: PatientLifecycleSource) {
  const surgeryEvents = patient.surgeries.map((surgery, index, surgeries) => ({
    eventType: 'SURGERY' as const,
    occurredAt: surgery.surgeryDate,
    hospital: patient.hospital,
    surgery: {
      id: toJsonNumber(surgery.id),
      surgeryDate: surgery.surgeryDate,
      surgeryName: surgery.surgeryName,
      surgeonName: surgery.surgeonName,
      primaryDisease: surgery.primaryDisease,
      hydrocephalusTypes: surgery.hydrocephalusTypes,
      previousShuntSurgeryDate: surgery.previousShuntSurgeryDate,
      shuntSurgeryCount: surgeries.length - index,
    },
    devices: surgery.devices.map((device) => ({
      id: toJsonNumber(device.id),
      status: device.status,
      isAbandoned: device.isAbandoned,
      currentPressure: device.currentPressure,
      initialPressure: device.initialPressure,
      implantModel: device.implantModel,
      implantManufacturer: device.implantManufacturer,
      implantName: device.implantName,
      isValve: device.isValve,
      isPressureAdjustable: device.isPressureAdjustable,
      shuntMode: device.shuntMode,
      distalShuntDirection: device.distalShuntDirection,
      proximalPunctureAreas: device.proximalPunctureAreas,
      valvePlacementSites: device.valvePlacementSites,
      implantCatalog: device.implantCatalog,
    })),
  }));

  const taskEvents = patient.devices.flatMap((device) =>
    device.taskItems.flatMap((taskItem) => {
      if (!taskItem.task) {
        return [];
      }

      const task = taskItem.task;
      return [
        {
          eventType: 'TASK_PRESSURE_ADJUSTMENT' as const,
          occurredAt: task.createdAt,
          hospital: patient.hospital,
          device: {
            id: toJsonNumber(device.id),
            status: device.status,
            isAbandoned: device.isAbandoned,
            currentPressure: device.currentPressure,
            implantModel: device.implantModel,
            implantManufacturer: device.implantManufacturer,
            implantName: device.implantName,
            isValve: device.isValve,
            isPressureAdjustable: device.isPressureAdjustable,
          },
          surgery: device.surgery
            ? {
                id: toJsonNumber(device.surgery.id),
                surgeryDate: device.surgery.surgeryDate,
                surgeryName: device.surgery.surgeryName,
              }
            : null,
          task: {
            id: toJsonNumber(task.id),
            status: task.status,
            createdAt: task.createdAt,
          },
          taskItem: {
            id: toJsonNumber(taskItem.id),
            oldPressure: taskItem.oldPressure,
            targetPressure: taskItem.targetPressure,
          },
        },
      ];
    }),
  );

  return [...surgeryEvents, ...taskEvents].sort(
    (left, right) =>
      new Date(right.occurredAt).getTime() -
      new Date(left.occurredAt).getTime(),
  );
}

function toJsonNumber(value: number | bigint | null | undefined) {
  if (value == null) {
    return null;
  }

  return typeof value === 'bigint' ? Number(value) : value;
}
