import { and, desc, eq, inArray, or } from "drizzle-orm";

import { getDatabase } from "@/modules/core/server/db";
import { careTasks, healthAnomalyReviews, systemIncidents, vitalRecords } from "@/modules/core/server/schema";
import type { Admission, FacilityBed, Permission } from "@/modules/core/types";
import type { Elder } from "@/modules/elders/types";
import { CARE_LEVEL_LABELS, ELDER_STATUS_LABELS } from "@/modules/elders/types";
import { CARE_TASK_STATUS_LABELS, CARE_TASK_TYPE_LABELS } from "@/modules/care/types";
import { HEALTH_REVIEW_SEVERITY_LABELS, HEALTH_REVIEW_STATUS_LABELS } from "@/modules/health/types";
import { INCIDENT_SEVERITY_LABELS, INCIDENT_STATUS_LABELS } from "@/modules/emergency/types";
import type { BedOperationalContext, ElderBedContextData, ElderOperationalContext, OperationalContextLine } from "@/modules/operations/types";

type ContextInput = {
  admissions: Admission[];
  beds: FacilityBed[];
  elders: Elder[];
  organizationId: string;
  permissions: readonly Permission[];
};

function hasPermission(permissions: readonly Permission[], permission: Permission): boolean {
  return permissions.includes(permission);
}

function addLine(target: { lines: OperationalContextLine[] }, line: OperationalContextLine): void {
  if (target.lines.length >= 3) {
    return;
  }

  target.lines.push(line);
}

function includesText(source: string, token: string): boolean {
  return token.length > 0 && source.includes(token);
}

export async function listElderBedContextData(input: ContextInput): Promise<ElderBedContextData> {
  const { admissions, beds, elders: elderList, organizationId, permissions } = input;
  const elderContexts = Object.fromEntries(elderList.map((elder) => [elder.id, { lines: [] }])) as Record<string, ElderOperationalContext>;
  const bedContexts = Object.fromEntries(beds.map((bed) => [bed.id, { lines: [] }])) as Record<string, BedOperationalContext>;
  const elderById = new Map(elderList.map((elder) => [elder.id, elder]));
  const activeAdmissions = admissions.filter((admission) => admission.status === "active");

  for (const admission of activeAdmissions) {
    const elder = elderById.get(admission.elderId);
    const bedContext = bedContexts[admission.bedId];
    if (!elder || !bedContext) {
      continue;
    }

    bedContext.occupant = {
      elderName: elder.name,
      careLevel: CARE_LEVEL_LABELS[elder.careLevel],
      status: ELDER_STATUS_LABELS[elder.status],
    };
  }

  const database = getDatabase();
  const elderIds = elderList.map((elder) => elder.id);
  if (elderIds.length === 0) {
    return { bedContexts, elderContexts };
  }

  const [careRows, reviewRows, vitalRows, incidentRows] = await Promise.all([
    hasPermission(permissions, "care:read")
      ? database
          .select()
          .from(careTasks)
          .where(and(eq(careTasks.organizationId, organizationId), inArray(careTasks.elderId, elderIds)))
          .orderBy(desc(careTasks.scheduledAt))
          .limit(60)
      : [],
    hasPermission(permissions, "health:read")
      ? database
          .select()
          .from(healthAnomalyReviews)
          .where(and(eq(healthAnomalyReviews.organizationId, organizationId), inArray(healthAnomalyReviews.elderId, elderIds)))
          .orderBy(desc(healthAnomalyReviews.createdAt))
          .limit(60)
      : [],
    hasPermission(permissions, "health:read")
      ? database
          .select()
          .from(vitalRecords)
          .where(and(eq(vitalRecords.organizationId, organizationId), inArray(vitalRecords.elderId, elderIds)))
          .orderBy(desc(vitalRecords.recordedAt))
          .limit(60)
      : [],
    hasPermission(permissions, "incident:read")
      ? database
          .select()
          .from(systemIncidents)
          .where(
            and(
              eq(systemIncidents.organizationId, organizationId),
              or(eq(systemIncidents.status, "open"), eq(systemIncidents.status, "acknowledged")),
            ),
          )
          .orderBy(desc(systemIncidents.createdAt))
          .limit(60)
      : [],
  ]);

  const bedIdByElderId = new Map(activeAdmissions.map((admission) => [admission.elderId, admission.bedId]));
  const seenCareElders = new Set<string>();
  for (const task of careRows) {
    if (!task.elderId || seenCareElders.has(task.elderId)) {
      continue;
    }

    const line: OperationalContextLine = {
      kind: "care",
      label: "护理",
      value: `${CARE_TASK_TYPE_LABELS[task.careType]} / ${CARE_TASK_STATUS_LABELS[task.status]}`,
      tone: task.status === "pending" || task.status === "in_progress" ? "warning" : "muted",
    };
    const elderContext = elderContexts[task.elderId];
    if (elderContext) {
      addLine(elderContext, line);
    }
    const bedId = bedIdByElderId.get(task.elderId);
    const bedContext = bedId ? bedContexts[bedId] : undefined;
    if (bedContext) {
      addLine(bedContext, line);
    }
    seenCareElders.add(task.elderId);
  }

  const seenReviewElders = new Set<string>();
  for (const review of reviewRows) {
    if (seenReviewElders.has(review.elderId)) {
      continue;
    }

    const line: OperationalContextLine = {
      kind: "health",
      label: "健康",
      value: `${HEALTH_REVIEW_SEVERITY_LABELS[review.severity]} / ${HEALTH_REVIEW_STATUS_LABELS[review.status]}：${review.title}`,
      tone: review.severity === "critical" ? "danger" : "warning",
    };
    const elderContext = elderContexts[review.elderId];
    if (elderContext) {
      addLine(elderContext, line);
    }
    const bedId = bedIdByElderId.get(review.elderId);
    const bedContext = bedId ? bedContexts[bedId] : undefined;
    if (bedContext) {
      addLine(bedContext, line);
    }
    seenReviewElders.add(review.elderId);
  }

  const seenVitalElders = new Set<string>();
  for (const vital of vitalRows) {
    if (seenReviewElders.has(vital.elderId) || seenVitalElders.has(vital.elderId)) {
      continue;
    }

    const bp = vital.systolicBp && vital.diastolicBp ? `血压 ${vital.systolicBp}/${vital.diastolicBp}` : "";
    const spo2 = vital.spo2 === null ? "" : `血氧 ${vital.spo2}%`;
    const value = [bp, spo2].filter(Boolean).join(" · ") || "最近体征已记录";
    const line: OperationalContextLine = { kind: "health", label: "体征", value, tone: "muted" };
    const elderContext = elderContexts[vital.elderId];
    if (elderContext) {
      addLine(elderContext, line);
    }
    seenVitalElders.add(vital.elderId);
  }

  for (const incident of incidentRows) {
    const haystack = [incident.title, incident.description, incident.source].join(" ");
    for (const elder of elderList) {
      const bedId = bedIdByElderId.get(elder.id);
      const bed = bedId ? beds.find((item) => item.id === bedId) : undefined;
      const matchesElder = includesText(haystack, elder.name);
      const matchesBed = bed ? includesText(haystack, bed.code) || includesText(haystack, bed.roomName) : false;
      if (!matchesElder && !matchesBed) {
        continue;
      }

      const line: OperationalContextLine = {
        kind: "incident",
        label: "应急",
        value: `${INCIDENT_SEVERITY_LABELS[incident.severity]} / ${INCIDENT_STATUS_LABELS[incident.status]}：${incident.title}`,
        tone: incident.severity === "critical" ? "danger" : "warning",
      };
      const elderContext = elderContexts[elder.id];
      if (elderContext) {
        addLine(elderContext, line);
      }
      const bedContext = bedId ? bedContexts[bedId] : undefined;
      if (bedContext) {
        addLine(bedContext, line);
      }
    }
  }

  return { bedContexts, elderContexts };
}
