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

import { getDatabase } from "@/modules/core/server/db";
import {
  accounts,
  chronicConditions,
  elders,
  healthAnomalyReviews,
  healthProfiles,
  vitalRecords,
} from "@/modules/core/server/schema";
import type {
  ChronicCondition,
  ChronicConditionInput,
  HealthAdminData,
  HealthAnomalyReview,
  HealthProfile,
  HealthProfileInput,
  HealthReviewUpdateInput,
  VitalRecord,
  VitalRecordInput,
} from "@/modules/health/types";

export type MutationFailure = {
  success: false;
  reason: string;
  status: number;
};

type ElderRow = typeof elders.$inferSelect;
type AccountNameRow = {
  id: string;
  name: string;
};

export function isMutationFailure(value: unknown): value is MutationFailure {
  return (
    typeof value === "object" &&
    value !== null &&
    "success" in value &&
    (value as { success?: unknown }).success === false
  );
}

function iso(value: Date): string {
  return value.toISOString();
}

function optionalIso(value: Date | null): string | undefined {
  return value ? iso(value) : undefined;
}

function buildNameMap(rows: AccountNameRow[]): Map<string, string> {
  return new Map(rows.map((row) => [row.id, row.name]));
}

function toProfile(row: typeof healthProfiles.$inferSelect, elderName: string): HealthProfile {
  return {
    id: row.id,
    organizationId: row.organizationId,
    elderId: row.elderId,
    elderName,
    allergyNotes: row.allergyNotes,
    medicalHistory: row.medicalHistory,
    medicationNotes: row.medicationNotes,
    careRestrictions: row.careRestrictions,
    emergencyNotes: row.emergencyNotes,
    createdAt: iso(row.createdAt),
    updatedAt: iso(row.updatedAt),
  };
}

function toVital(row: typeof vitalRecords.$inferSelect, elderName: string, accountNameById: Map<string, string>): VitalRecord {
  return {
    id: row.id,
    organizationId: row.organizationId,
    elderId: row.elderId,
    elderName,
    recordedAt: iso(row.recordedAt),
    source: row.source,
    systolicBp: row.systolicBp ?? undefined,
    diastolicBp: row.diastolicBp ?? undefined,
    heartRate: row.heartRate ?? undefined,
    temperatureTenths: row.temperatureTenths ?? undefined,
    spo2: row.spo2 ?? undefined,
    bloodGlucoseTenths: row.bloodGlucoseTenths ?? undefined,
    weightTenths: row.weightTenths ?? undefined,
    notes: row.notes,
    createdByAccountId: row.createdByAccountId ?? undefined,
    createdByName: row.createdByAccountId ? accountNameById.get(row.createdByAccountId) : undefined,
    createdAt: iso(row.createdAt),
    updatedAt: iso(row.updatedAt),
  };
}

function toCondition(row: typeof chronicConditions.$inferSelect, elderName: string): ChronicCondition {
  return {
    id: row.id,
    organizationId: row.organizationId,
    elderId: row.elderId,
    elderName,
    name: row.name,
    status: row.status,
    diagnosedAt: optionalIso(row.diagnosedAt),
    treatmentNotes: row.treatmentNotes,
    followUpNotes: row.followUpNotes,
    createdAt: iso(row.createdAt),
    updatedAt: iso(row.updatedAt),
  };
}

function toReview(
  row: typeof healthAnomalyReviews.$inferSelect,
  elderName: string,
  accountNameById: Map<string, string>,
): HealthAnomalyReview {
  return {
    id: row.id,
    organizationId: row.organizationId,
    elderId: row.elderId,
    elderName,
    vitalRecordId: row.vitalRecordId ?? undefined,
    severity: row.severity,
    status: row.status,
    title: row.title,
    description: row.description,
    reviewedByAccountId: row.reviewedByAccountId ?? undefined,
    reviewedByName: row.reviewedByAccountId ? accountNameById.get(row.reviewedByAccountId) : undefined,
    reviewedAt: optionalIso(row.reviewedAt),
    resolutionNotes: row.resolutionNotes,
    createdAt: iso(row.createdAt),
    updatedAt: iso(row.updatedAt),
  };
}

function getElderName(row: ElderRow | undefined): string {
  return row?.name ?? "";
}

async function findElder(organizationId: string, elderId: string): Promise<ElderRow | undefined> {
  const database = getDatabase();
  const rows = await database
    .select()
    .from(elders)
    .where(and(eq(elders.id, elderId), eq(elders.organizationId, organizationId)))
    .limit(1);
  return rows[0];
}

function detectVitalAnomaly(input: VitalRecordInput): { title: string; description: string; severity: "warning" | "critical" } | null {
  if ((input.systolicBp !== undefined && input.systolicBp >= 180) || (input.diastolicBp !== undefined && input.diastolicBp >= 110)) {
    return { title: "血压严重异常", description: "血压达到紧急复核阈值", severity: "critical" };
  }

  if ((input.systolicBp !== undefined && input.systolicBp >= 150) || (input.diastolicBp !== undefined && input.diastolicBp >= 95)) {
    return { title: "血压异常", description: "血压偏高，需要护理人员复核", severity: "warning" };
  }

  if (input.temperatureTenths !== undefined && input.temperatureTenths >= 380) {
    return { title: "体温异常", description: "体温偏高，需要复核", severity: "warning" };
  }

  if (input.spo2 !== undefined && input.spo2 < 92) {
    return { title: "血氧异常", description: "血氧偏低，需要复核", severity: "critical" };
  }

  return null;
}

export async function listHealthAdminData(organizationId: string): Promise<HealthAdminData> {
  const database = getDatabase();
  const todayStart = new Date();
  todayStart.setHours(0, 0, 0, 0);

  const [elderRows, profileRows, vitalRows, conditionRows, reviewRows, accountRows] = await Promise.all([
    database.select().from(elders).where(eq(elders.organizationId, organizationId)).orderBy(desc(elders.createdAt)),
    database.select().from(healthProfiles).where(eq(healthProfiles.organizationId, organizationId)).orderBy(desc(healthProfiles.updatedAt)),
    database.select().from(vitalRecords).where(eq(vitalRecords.organizationId, organizationId)).orderBy(desc(vitalRecords.recordedAt)).limit(100),
    database
      .select()
      .from(chronicConditions)
      .where(eq(chronicConditions.organizationId, organizationId))
      .orderBy(desc(chronicConditions.updatedAt)),
    database
      .select()
      .from(healthAnomalyReviews)
      .where(eq(healthAnomalyReviews.organizationId, organizationId))
      .orderBy(desc(healthAnomalyReviews.createdAt)),
    database.select({ id: accounts.id, name: accounts.name }).from(accounts),
  ]);

  const elderById = new Map(elderRows.map((elder) => [elder.id, elder]));
  const accountNameById = buildNameMap(accountRows);

  return {
    elders: elderRows.map((elder) => ({
      id: elder.id,
      name: elder.name,
      careLevel: elder.careLevel,
      status: elder.status,
    })),
    profiles: profileRows.map((profile) => toProfile(profile, getElderName(elderById.get(profile.elderId)))),
    vitals: vitalRows.map((vital) => toVital(vital, getElderName(elderById.get(vital.elderId)), accountNameById)),
    chronicConditions: conditionRows.map((condition) => toCondition(condition, getElderName(elderById.get(condition.elderId)))),
    reviews: reviewRows.map((review) => toReview(review, getElderName(elderById.get(review.elderId)), accountNameById)),
    metrics: {
      eldersWithProfiles: profileRows.length,
      vitalsToday: vitalRows.filter((vital) => vital.recordedAt >= todayStart).length,
      activeChronicConditions: conditionRows.filter((condition) => condition.status === "active").length,
      pendingReviews: reviewRows.filter((review) => review.status === "pending").length,
    },
  };
}

export async function upsertHealthProfile(input: HealthProfileInput & { elderId: string; organizationId: string }): Promise<HealthProfile | MutationFailure> {
  const elder = await findElder(input.organizationId, input.elderId);
  if (!elder) {
    return { success: false, reason: "老人档案不存在", status: 404 };
  }

  const database = getDatabase();
  const rows = await database
    .insert(healthProfiles)
    .values({
      organizationId: input.organizationId,
      elderId: input.elderId,
      allergyNotes: input.allergyNotes,
      medicalHistory: input.medicalHistory,
      medicationNotes: input.medicationNotes,
      careRestrictions: input.careRestrictions,
      emergencyNotes: input.emergencyNotes,
    })
    .onConflictDoUpdate({
      target: [healthProfiles.organizationId, healthProfiles.elderId],
      set: {
        allergyNotes: input.allergyNotes,
        medicalHistory: input.medicalHistory,
        medicationNotes: input.medicationNotes,
        careRestrictions: input.careRestrictions,
        emergencyNotes: input.emergencyNotes,
        updatedAt: sql`NOW()`,
      },
    })
    .returning();
  const profile = rows[0];
  if (!profile) {
    return { success: false, reason: "健康档案保存失败", status: 500 };
  }

  return toProfile(profile, elder.name);
}

export async function createVitalRecord(input: VitalRecordInput & { accountId: string; organizationId: string }): Promise<
  | {
      vital: VitalRecord;
      review?: HealthAnomalyReview;
    }
  | MutationFailure
> {
  const elder = await findElder(input.organizationId, input.elderId);
  if (!elder) {
    return { success: false, reason: "老人档案不存在", status: 404 };
  }

  const database = getDatabase();
  const created = await database.transaction(async (transaction) => {
    const vitalRows = await transaction
      .insert(vitalRecords)
      .values({
        organizationId: input.organizationId,
        elderId: input.elderId,
        recordedAt: input.recordedAt,
        source: input.source,
        systolicBp: input.systolicBp,
        diastolicBp: input.diastolicBp,
        heartRate: input.heartRate,
        temperatureTenths: input.temperatureTenths,
        spo2: input.spo2,
        bloodGlucoseTenths: input.bloodGlucoseTenths,
        weightTenths: input.weightTenths,
        notes: input.notes,
        createdByAccountId: input.accountId,
      })
      .returning();
    const vital = vitalRows[0];
    if (!vital) {
      return null;
    }

    const anomaly = detectVitalAnomaly(input);
    if (!anomaly) {
      return { vital };
    }

    const reviewRows = await transaction
      .insert(healthAnomalyReviews)
      .values({
        organizationId: input.organizationId,
        elderId: input.elderId,
        vitalRecordId: vital.id,
        severity: anomaly.severity,
        status: "pending",
        title: anomaly.title,
        description: anomaly.description,
      })
      .returning();
    return { vital, review: reviewRows[0] };
  });

  if (!created) {
    return { success: false, reason: "生命体征记录创建失败", status: 500 };
  }

  const accountRows = await database.select({ id: accounts.id, name: accounts.name }).from(accounts).where(eq(accounts.id, input.accountId));
  const accountNameById = buildNameMap(accountRows);

  return {
    vital: toVital(created.vital, elder.name, accountNameById),
    review: created.review ? toReview(created.review, elder.name, accountNameById) : undefined,
  };
}

export async function createChronicCondition(
  input: ChronicConditionInput & { organizationId: string },
): Promise<ChronicCondition | MutationFailure> {
  const elder = await findElder(input.organizationId, input.elderId);
  if (!elder) {
    return { success: false, reason: "老人档案不存在", status: 404 };
  }

  const database = getDatabase();
  const rows = await database
    .insert(chronicConditions)
    .values({
      organizationId: input.organizationId,
      elderId: input.elderId,
      name: input.name,
      status: input.status,
      diagnosedAt: input.diagnosedAt,
      treatmentNotes: input.treatmentNotes,
      followUpNotes: input.followUpNotes,
    })
    .returning();
  const condition = rows[0];
  if (!condition) {
    return { success: false, reason: "慢病记录创建失败", status: 500 };
  }

  return toCondition(condition, elder.name);
}

export async function updateHealthReview(input: HealthReviewUpdateInput & { accountId: string; id: string; organizationId: string }): Promise<
  HealthAnomalyReview | MutationFailure
> {
  const database = getDatabase();
  const rows = await database
    .update(healthAnomalyReviews)
    .set({
      status: input.status,
      resolutionNotes: input.resolutionNotes,
      reviewedByAccountId: input.accountId,
      reviewedAt: new Date(),
      updatedAt: new Date(),
    })
    .where(and(eq(healthAnomalyReviews.id, input.id), eq(healthAnomalyReviews.organizationId, input.organizationId)))
    .returning();
  const review = rows[0];
  if (!review) {
    return { success: false, reason: "异常复核记录不存在", status: 404 };
  }

  const [elderRows, accountRows] = await Promise.all([
    database.select().from(elders).where(eq(elders.id, review.elderId)).limit(1),
    database.select({ id: accounts.id, name: accounts.name }).from(accounts).where(eq(accounts.id, input.accountId)),
  ]);

  return toReview(review, getElderName(elderRows[0]), buildNameMap(accountRows));
}
