"use client";

import { FormEvent, useMemo, useState } from "react";
import { BedDouble, DoorOpen, History, MoveRight, UserCheck, UserMinus, Wrench } from "lucide-react";

import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Dialog } from "@/components/ui/dialog";
import { Textarea } from "@/components/ui/input";
import { Select, type SelectOption } from "@/components/ui/select";
import { Table } from "@/components/ui/table";
import { cn } from "@/lib/utils";
import type { ApiResult } from "@/modules/core/server/api";
import type { Admission, BedStatus, FacilityBed, Permission, Room } from "@/modules/core/types";
import type { Elder } from "@/modules/elders/types";
import type { BedOperationalContext, OperationalContextLine } from "@/modules/operations/types";

type BedsWorkspaceProps = {
  bedContexts?: Record<string, BedOperationalContext>;
  initialRooms: Room[];
  initialBeds: FacilityBed[];
  initialAdmissions: Admission[];
  initialElders: Elder[];
  permissions: Permission[];
};

type WorkspaceTab = "overview" | "operations" | "history";
type BedDetailTab = "context" | "records" | "actions";
type RoomView = {
  room: Room;
  beds: FacilityBed[];
};

const workspaceTabs: Array<{ value: WorkspaceTab; label: string }> = [
  { value: "overview", label: "概览" },
  { value: "operations", label: "办理" },
  { value: "history", label: "记录" },
];

const bedDetailTabs: Array<{ value: BedDetailTab; label: string }> = [
  { value: "context", label: "上下文" },
  { value: "records", label: "流水记录" },
  { value: "actions", label: "专项办理" },
];

const bedStatusLabels: Record<BedStatus, string> = {
  available: "空闲",
  occupied: "占用",
  maintenance: "维修",
  disabled: "停用",
};

const admissionStatusLabels: Record<Admission["status"], string> = {
  active: "在住",
  transferred: "已换床",
  discharged: "已退住",
};

const contextKindLabels: Record<OperationalContextLine["kind"], string> = {
  admission: "入住",
  care: "照护",
  health: "健康",
  incident: "预警",
};

function formatDateTime(value: string): string {
  return new Date(value).toLocaleString("zh-CN");
}

function bedBadgeVariant(status: BedStatus): "success" | "secondary" | "warning" | "danger" {
  switch (status) {
    case "available":
      return "success";
    case "occupied":
      return "secondary";
    case "maintenance":
      return "warning";
    case "disabled":
      return "danger";
  }
}

function admissionBedLabel(admission: Admission): string {
  return `${admission.roomName}-${admission.bedCode}`;
}

function buildRoomViews(rooms: Room[], beds: FacilityBed[]): RoomView[] {
  const bedsByRoomId = new Map<string, FacilityBed[]>();
  for (const bed of beds) {
    const roomBeds = bedsByRoomId.get(bed.roomId) ?? [];
    roomBeds.push(bed);
    bedsByRoomId.set(bed.roomId, roomBeds);
  }

  return [...rooms]
    .sort((first, second) => first.code.localeCompare(second.code, "zh-CN", { numeric: true }))
    .map((room) => ({
      room,
      beds: (bedsByRoomId.get(room.id) ?? []).sort((first, second) =>
        first.code.localeCompare(second.code, "zh-CN", { numeric: true }),
      ),
    }));
}

function makeSelectOptions(items: Array<{ id: string; label: string }>, emptyLabel: string): SelectOption[] {
  return [
    { value: "", label: emptyLabel, disabled: true },
    ...items.map((item) => ({ value: item.id, label: item.label })),
  ];
}

function bedTileClass(status: BedStatus): string {
  switch (status) {
    case "available":
      return "border-emerald-200 bg-emerald-50 text-emerald-900 hover:border-emerald-400";
    case "occupied":
      return "border-zinc-200 bg-zinc-50 text-zinc-900 hover:border-zinc-400";
    case "maintenance":
      return "border-amber-200 bg-amber-50 text-amber-950 hover:border-amber-400";
    case "disabled":
      return "border-rose-200 bg-rose-50 text-rose-950 hover:border-rose-400";
  }
}

function statusDotClass(status: BedStatus): string {
  switch (status) {
    case "available":
      return "bg-emerald-500";
    case "occupied":
      return "bg-zinc-500";
    case "maintenance":
      return "bg-amber-500";
    case "disabled":
      return "bg-rose-500";
  }
}

export function BedsWorkspace({
  bedContexts = {},
  initialRooms,
  initialBeds,
  initialAdmissions,
  initialElders,
  permissions,
}: BedsWorkspaceProps): React.ReactElement {
  const [rooms, setRooms] = useState(initialRooms);
  const [beds, setBeds] = useState(initialBeds);
  const [admissions, setAdmissions] = useState(initialAdmissions);
  const [elders, setElders] = useState(initialElders);
  const [activeTab, setActiveTab] = useState<WorkspaceTab>("overview");
  const [message, setMessage] = useState("");
  const [isPending, setIsPending] = useState(false);
  const [admitElderId, setAdmitElderId] = useState("");
  const [admitBedId, setAdmitBedId] = useState("");
  const [admitNotes, setAdmitNotes] = useState("");
  const [transferAdmissionId, setTransferAdmissionId] = useState("");
  const [transferBedId, setTransferBedId] = useState("");
  const [transferNotes, setTransferNotes] = useState("");
  const [dischargeAdmissionId, setDischargeAdmissionId] = useState("");
  const [dischargeNotes, setDischargeNotes] = useState("");
  const [selectedBedId, setSelectedBedId] = useState("");
  const [bedDetailTab, setBedDetailTab] = useState<BedDetailTab>("context");

  const canManageAdmissions = permissions.includes("admission:manage");
  const activeAdmissions = useMemo(() => admissions.filter((admission) => admission.status === "active"), [admissions]);
  const activeElderIds = useMemo(() => new Set(activeAdmissions.map((admission) => admission.elderId)), [activeAdmissions]);
  const availableBeds = useMemo(() => beds.filter((bed) => bed.status === "available"), [beds]);
  const occupiedBeds = beds.filter((bed) => bed.status === "occupied").length;
  const maintenanceBeds = beds.filter((bed) => bed.status === "maintenance").length;
  const occupancyRate = beds.length > 0 ? Math.round((occupiedBeds / beds.length) * 100) : 0;
  const admissionEligibleElders = elders.filter((elder) => !activeElderIds.has(elder.id));
  const roomViews = useMemo(() => buildRoomViews(rooms, beds), [rooms, beds]);
  const selectedBed = useMemo(() => beds.find((bed) => bed.id === selectedBedId), [beds, selectedBedId]);
  const selectedAdmission = selectedBed
    ? activeAdmissions.find((admission) => admission.bedId === selectedBed.id)
    : undefined;
  const selectedBedAdmissions = selectedBed
    ? admissions.filter((admission) => admission.bedId === selectedBed.id)
    : [];
  const selectedBedContext = selectedBed ? bedContexts[selectedBed.id] : undefined;

  const elderOptions = makeSelectOptions(
    admissionEligibleElders.map((elder) => ({ id: elder.id, label: `${elder.name} / ${elder.phone}` })),
    "选择老人",
  );
  const bedOptions = makeSelectOptions(
    availableBeds.map((bed) => ({ id: bed.id, label: `${bed.roomName}-${bed.code}` })),
    "选择空闲床位",
  );
  const activeAdmissionOptions = makeSelectOptions(
    activeAdmissions.map((admission) => ({
      id: admission.id,
      label: `${admission.elderName} / ${admissionBedLabel(admission)}`,
    })),
    "选择在住记录",
  );

  function openBedDetail(bed: FacilityBed, initialTab: BedDetailTab = "context"): void {
    setSelectedBedId(bed.id);
    setBedDetailTab(initialTab);
  }

  function startAdmissionFromBed(bed: FacilityBed): void {
    setAdmitBedId(bed.id);
    setSelectedBedId(bed.id);
    setBedDetailTab("actions");
  }

  async function refreshData(): Promise<void> {
    const [eldersResponse, roomsResponse, bedsResponse, admissionsResponse] = await Promise.all([
      fetch("/api/elders"),
      fetch("/api/facilities/rooms"),
      fetch("/api/facilities/beds"),
      fetch("/api/admissions"),
    ]);
    const [eldersResult, roomsResult, bedsResult, admissionsResult] = (await Promise.all([
      eldersResponse.json(),
      roomsResponse.json(),
      bedsResponse.json(),
      admissionsResponse.json(),
    ])) as [
      ApiResult<{ elders: Elder[] }>,
      ApiResult<{ rooms: Room[] }>,
      ApiResult<{ beds: FacilityBed[] }>,
      ApiResult<{ admissions: Admission[] }>,
    ];

    if (eldersResult.success) {
      setElders(eldersResult.elders);
    }
    if (roomsResult.success) {
      setRooms(roomsResult.rooms);
    }
    if (bedsResult.success) {
      setBeds(bedsResult.beds);
    }
    if (admissionsResult.success) {
      setAdmissions(admissionsResult.admissions);
    }
  }

  async function submitAdmission(event: FormEvent<HTMLFormElement>): Promise<void> {
    event.preventDefault();
    if (!canManageAdmissions) {
      setMessage("当前角色无权办理入住");
      return;
    }
    if (!admitElderId || !admitBedId) {
      setMessage("请选择老人和空闲床位");
      return;
    }

    setIsPending(true);
    setMessage("");
    const response = await fetch("/api/admissions", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ elderId: admitElderId, bedId: admitBedId, notes: admitNotes }),
    });
    const result = (await response.json()) as ApiResult<{ admission: Admission }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setAdmitElderId("");
    setAdmitBedId("");
    setAdmitNotes("");
    await refreshData();
    setMessage(result.reason);
  }

  async function submitAdmissionForBed(event: FormEvent<HTMLFormElement>, bed: FacilityBed): Promise<void> {
    event.preventDefault();
    if (!canManageAdmissions) {
      setMessage("当前角色无权办理入住");
      return;
    }
    if (bed.status !== "available") {
      setMessage("当前床位不可办理入住");
      return;
    }
    if (!admitElderId) {
      setMessage("请选择老人");
      return;
    }

    setIsPending(true);
    setMessage("");
    const response = await fetch("/api/admissions", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ elderId: admitElderId, bedId: bed.id, notes: admitNotes }),
    });
    const result = (await response.json()) as ApiResult<{ admission: Admission }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setAdmitElderId("");
    setAdmitBedId("");
    setAdmitNotes("");
    await refreshData();
    setMessage(result.reason);
  }

  async function submitTransfer(event: FormEvent<HTMLFormElement>): Promise<void> {
    event.preventDefault();
    const admission = activeAdmissions.find((item) => item.id === transferAdmissionId);
    if (!canManageAdmissions) {
      setMessage("当前角色无权办理换床");
      return;
    }
    if (!admission || !transferBedId) {
      setMessage("请选择在住记录和新床位");
      return;
    }

    setIsPending(true);
    setMessage("");
    const response = await fetch("/api/admissions", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ elderId: admission.elderId, bedId: transferBedId, notes: transferNotes || "办理换床" }),
    });
    const result = (await response.json()) as ApiResult<{ admission: Admission }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setTransferAdmissionId("");
    setTransferBedId("");
    setTransferNotes("");
    await refreshData();
    setMessage("换床已办理");
  }

  async function submitTransferForAdmission(event: FormEvent<HTMLFormElement>, admission: Admission): Promise<void> {
    event.preventDefault();
    if (!canManageAdmissions) {
      setMessage("当前角色无权办理换床");
      return;
    }
    if (!transferBedId) {
      setMessage("请选择新床位");
      return;
    }

    setIsPending(true);
    setMessage("");
    const response = await fetch("/api/admissions", {
      method: "POST",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ elderId: admission.elderId, bedId: transferBedId, notes: transferNotes || "办理换床" }),
    });
    const result = (await response.json()) as ApiResult<{ admission: Admission }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setTransferAdmissionId("");
    setTransferBedId("");
    setTransferNotes("");
    await refreshData();
    setMessage("换床已办理");
  }

  async function submitDischarge(event: FormEvent<HTMLFormElement>): Promise<void> {
    event.preventDefault();
    if (!canManageAdmissions) {
      setMessage("当前角色无权办理退住");
      return;
    }
    if (!dischargeAdmissionId) {
      setMessage("请选择在住记录");
      return;
    }

    setIsPending(true);
    setMessage("");
    const response = await fetch(`/api/admissions/${dischargeAdmissionId}`, {
      method: "PATCH",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ notes: dischargeNotes }),
    });
    const result = (await response.json()) as ApiResult<{ admission: Admission }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setDischargeAdmissionId("");
    setDischargeNotes("");
    await refreshData();
    setMessage(result.reason);
  }

  async function submitDischargeForAdmission(event: FormEvent<HTMLFormElement>, admission: Admission): Promise<void> {
    event.preventDefault();
    if (!canManageAdmissions) {
      setMessage("当前角色无权办理退住");
      return;
    }

    setIsPending(true);
    setMessage("");
    const response = await fetch(`/api/admissions/${admission.id}`, {
      method: "PATCH",
      headers: { "content-type": "application/json" },
      body: JSON.stringify({ notes: dischargeNotes }),
    });
    const result = (await response.json()) as ApiResult<{ admission: Admission }>;
    setIsPending(false);

    if (!result.success) {
      setMessage(result.reason);
      return;
    }

    setDischargeAdmissionId("");
    setDischargeNotes("");
    await refreshData();
    setMessage(result.reason);
  }

  return (
    <div className="mx-auto flex w-full max-w-7xl flex-col gap-5">
      <section className="flex border-b pb-4">
        <div className="flex flex-wrap gap-2" role="tablist" aria-label="床位工作区">
          {workspaceTabs.map((tab) => (
            <Button
              aria-selected={activeTab === tab.value}
              key={tab.value}
              onClick={() => setActiveTab(tab.value)}
              role="tab"
              type="button"
              variant={activeTab === tab.value ? "default" : "outline"}
            >
              {tab.label}
            </Button>
          ))}
        </div>
      </section>

      {message ? (
        <p className="rounded-md bg-secondary px-3 py-2 text-sm text-secondary-foreground" role="status">
          {message}
        </p>
      ) : null}

      {activeTab === "overview" ? (
        <>
          <section className="grid gap-4 md:grid-cols-2 xl:grid-cols-4">
            <Card>
              <CardHeader className="flex flex-row items-center justify-between space-y-0">
                <div>
                  <CardDescription>房间</CardDescription>
                  <CardTitle className="mt-2 text-3xl">{rooms.length}</CardTitle>
                </div>
                <DoorOpen className="size-5 text-primary" aria-hidden="true" />
              </CardHeader>
            </Card>
            <Card>
              <CardHeader className="flex flex-row items-center justify-between space-y-0">
                <div>
                  <CardDescription>床位</CardDescription>
                  <CardTitle className="mt-2 text-3xl">{beds.length}</CardTitle>
                </div>
                <BedDouble className="size-5 text-primary" aria-hidden="true" />
              </CardHeader>
              <CardContent className="pt-0">
                <p className="text-sm text-muted-foreground">占用率 {occupancyRate}%</p>
              </CardContent>
            </Card>
            <Card className={maintenanceBeds > 0 ? "border-amber-200 bg-amber-50/70" : undefined}>
              <CardHeader className="flex flex-row items-center justify-between space-y-0">
                <div>
                  <CardDescription className={maintenanceBeds > 0 ? "text-amber-700" : undefined}>维修床位</CardDescription>
                  <CardTitle className={maintenanceBeds > 0 ? "mt-2 text-3xl text-amber-700" : "mt-2 text-3xl"}>
                    {maintenanceBeds}
                  </CardTitle>
                </div>
                <Wrench className={maintenanceBeds > 0 ? "size-5 text-amber-700" : "size-5 text-primary"} aria-hidden="true" />
              </CardHeader>
            </Card>
            <Card>
              <CardHeader className="flex flex-row items-center justify-between space-y-0">
                <div>
                  <CardDescription>在住</CardDescription>
                  <CardTitle className="mt-2 text-3xl">{activeAdmissions.length}</CardTitle>
                </div>
                <History className="size-5 text-primary" aria-hidden="true" />
              </CardHeader>
            </Card>
          </section>

          <section className="grid gap-4 xl:grid-cols-[minmax(0,1fr)_20rem]">
            <Card>
              <CardHeader>
                <CardTitle>房间格子视图</CardTitle>
                <CardDescription>按房间查看床位占用、维修、停用和待入住空床。</CardDescription>
              </CardHeader>
              <CardContent className="grid gap-4">
                <StatusLegend />
                {roomViews.length > 0 ? (
                  <div className="grid gap-4 lg:grid-cols-2">
                    {roomViews.map((view) => (
                      <RoomGrid
                        bedContexts={bedContexts}
                        key={view.room.id}
                        onSelectBed={openBedDetail}
                        onStartAdmission={startAdmissionFromBed}
                        roomView={view}
                      />
                    ))}
                  </div>
                ) : (
                  <p className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">暂无房间主数据</p>
                )}
              </CardContent>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>快速办理</CardTitle>
                <CardDescription>空床格子可直接进入入住办理。</CardDescription>
              </CardHeader>
              <CardContent>
                <form className="grid gap-3" onSubmit={(event) => void submitAdmission(event)}>
                  <Select
                    aria-label="入住老人"
                    disabled={!canManageAdmissions || isPending}
                    onValueChange={setAdmitElderId}
                    options={elderOptions}
                    value={admitElderId}
                  />
                  <Select
                    aria-label="入住房间床位"
                    disabled={!canManageAdmissions || isPending}
                    onValueChange={setAdmitBedId}
                    options={bedOptions}
                    value={admitBedId}
                  />
                  <Textarea
                    aria-label="入住备注"
                    disabled={!canManageAdmissions || isPending}
                    onChange={(event) => setAdmitNotes(event.target.value)}
                    placeholder="备注"
                    value={admitNotes}
                  />
                  <Button disabled={!canManageAdmissions || isPending} type="submit">
                    <UserCheck className="size-4" aria-hidden="true" />
                    办理入住
                  </Button>
                </form>
              </CardContent>
            </Card>
          </section>
        </>
      ) : null}

      {activeTab === "operations" ? (
        <section className="grid gap-4 xl:grid-cols-3">
          <Card>
            <CardHeader>
              <CardTitle className="flex items-center gap-2">
                <UserCheck className="size-5 text-primary" aria-hidden="true" />
                办理入住
              </CardTitle>
              <CardDescription>选择未在住老人和空闲床位。</CardDescription>
            </CardHeader>
            <CardContent>
              <form className="grid gap-3" onSubmit={(event) => void submitAdmission(event)}>
                <Select
                  aria-label="入住老人"
                  disabled={!canManageAdmissions || isPending}
                  onValueChange={setAdmitElderId}
                  options={elderOptions}
                  value={admitElderId}
                />
                <Select
                  aria-label="入住房间床位"
                  disabled={!canManageAdmissions || isPending}
                  onValueChange={setAdmitBedId}
                  options={bedOptions}
                  value={admitBedId}
                />
                <Textarea
                  aria-label="入住备注"
                  disabled={!canManageAdmissions || isPending}
                  onChange={(event) => setAdmitNotes(event.target.value)}
                  placeholder="备注"
                  value={admitNotes}
                />
                <Button disabled={!canManageAdmissions || isPending} type="submit">
                  <UserCheck className="size-4" aria-hidden="true" />
                  办理入住
                </Button>
              </form>
            </CardContent>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle className="flex items-center gap-2">
                <MoveRight className="size-5 text-primary" aria-hidden="true" />
                办理换床
              </CardTitle>
              <CardDescription>换床会释放原床位并占用新床位。</CardDescription>
            </CardHeader>
            <CardContent>
              <form className="grid gap-3" onSubmit={(event) => void submitTransfer(event)}>
                <Select
                  aria-label="换床入住记录"
                  disabled={!canManageAdmissions || isPending}
                  onValueChange={setTransferAdmissionId}
                  options={activeAdmissionOptions}
                  value={transferAdmissionId}
                />
                <Select
                  aria-label="换床新床位"
                  disabled={!canManageAdmissions || isPending}
                  onValueChange={setTransferBedId}
                  options={bedOptions}
                  value={transferBedId}
                />
                <Textarea
                  aria-label="换床备注"
                  disabled={!canManageAdmissions || isPending}
                  onChange={(event) => setTransferNotes(event.target.value)}
                  placeholder="备注"
                  value={transferNotes}
                />
                <Button disabled={!canManageAdmissions || isPending} type="submit" variant="outline">
                  <MoveRight className="size-4" aria-hidden="true" />
                  办理换床
                </Button>
              </form>
            </CardContent>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle className="flex items-center gap-2">
                <UserMinus className="size-5 text-primary" aria-hidden="true" />
                办理退住
              </CardTitle>
              <CardDescription>退住会关闭入住记录并释放床位。</CardDescription>
            </CardHeader>
            <CardContent>
              <form className="grid gap-3" onSubmit={(event) => void submitDischarge(event)}>
                <Select
                  aria-label="退住入住记录"
                  disabled={!canManageAdmissions || isPending}
                  onValueChange={setDischargeAdmissionId}
                  options={activeAdmissionOptions}
                  value={dischargeAdmissionId}
                />
                <Textarea
                  aria-label="退住备注"
                  disabled={!canManageAdmissions || isPending}
                  onChange={(event) => setDischargeNotes(event.target.value)}
                  placeholder="备注"
                  value={dischargeNotes}
                />
                <Button disabled={!canManageAdmissions || isPending} type="submit" variant="destructive">
                  <UserMinus className="size-4" aria-hidden="true" />
                  办理退住
                </Button>
              </form>
            </CardContent>
          </Card>
        </section>
      ) : null}

      {activeTab === "history" ? (
        <Card>
          <CardHeader>
            <CardTitle>入住、换床与退住记录</CardTitle>
          </CardHeader>
          <CardContent>
            <div className="overflow-x-auto rounded-md border">
              <Table className="w-full min-w-[820px] text-sm">
                <Table.Header className="bg-secondary text-left text-xs text-muted-foreground">
                  <Table.Row>
                    <Table.Head className="px-4 py-3 font-medium">老人</Table.Head>
                    <Table.Head className="px-4 py-3 font-medium">床位</Table.Head>
                    <Table.Head className="px-4 py-3 font-medium">状态</Table.Head>
                    <Table.Head className="px-4 py-3 font-medium">入住时间</Table.Head>
                    <Table.Head className="px-4 py-3 font-medium">结束时间</Table.Head>
                    <Table.Head className="px-4 py-3 font-medium">备注</Table.Head>
                  </Table.Row>
                </Table.Header>
                <Table.Body className="divide-y bg-card">
                  {admissions.map((admission) => (
                    <Table.Row key={admission.id}>
                      <Table.Cell className="px-4 py-3 font-medium">{admission.elderName}</Table.Cell>
                      <Table.Cell className="px-4 py-3">{admissionBedLabel(admission)}</Table.Cell>
                      <Table.Cell className="px-4 py-3">
                        <Badge variant={admission.status === "active" ? "success" : "secondary"}>
                          {admissionStatusLabels[admission.status]}
                        </Badge>
                      </Table.Cell>
                      <Table.Cell className="px-4 py-3 text-muted-foreground">{formatDateTime(admission.admittedAt)}</Table.Cell>
                      <Table.Cell className="px-4 py-3 text-muted-foreground">
                        {admission.dischargedAt ? formatDateTime(admission.dischargedAt) : "-"}
                      </Table.Cell>
                      <Table.Cell className="px-4 py-3 text-muted-foreground">{admission.notes || "-"}</Table.Cell>
                    </Table.Row>
                  ))}
                  {admissions.length === 0 ? (
                    <Table.Row>
                      <Table.Cell className="px-4 py-8 text-center text-muted-foreground" colSpan={6}>
                        暂无入住记录
                      </Table.Cell>
                    </Table.Row>
                  ) : null}
                </Table.Body>
              </Table>
            </div>
          </CardContent>
        </Card>
      ) : null}

      <BedDetailDialog
        activeAdmission={selectedAdmission}
        activeTab={bedDetailTab}
        admissions={selectedBedAdmissions}
        bed={selectedBed}
        bedOptions={bedOptions}
        canManageAdmissions={canManageAdmissions}
        context={selectedBedContext}
        dischargeNotes={dischargeNotes}
        elderOptions={elderOptions}
        isPending={isPending}
        notes={admitNotes}
        onClose={() => setSelectedBedId("")}
        onDischargeNotesChange={setDischargeNotes}
        onElderChange={setAdmitElderId}
        onNotesChange={setAdmitNotes}
        onSubmitAdmission={submitAdmissionForBed}
        onSubmitDischarge={submitDischargeForAdmission}
        onSubmitTransfer={submitTransferForAdmission}
        onTabChange={setBedDetailTab}
        onTransferBedChange={setTransferBedId}
        onTransferNotesChange={setTransferNotes}
        selectedElderId={admitElderId}
        selectedTransferBedId={transferBedId}
        transferNotes={transferNotes}
      />
    </div>
  );
}

function StatusLegend(): React.ReactElement {
  return (
    <div className="flex flex-wrap gap-3 text-xs text-muted-foreground" aria-label="床位状态图例">
      {(["available", "occupied", "maintenance", "disabled"] as BedStatus[]).map((status) => (
        <span className="inline-flex items-center gap-2" key={status}>
          <span className={cn("size-2 rounded-full", statusDotClass(status))} aria-hidden="true" />
          {bedStatusLabels[status]}
        </span>
      ))}
    </div>
  );
}

function RoomGrid({
  bedContexts,
  onSelectBed,
  onStartAdmission,
  roomView,
}: {
  bedContexts: Record<string, BedOperationalContext>;
  onSelectBed: (bed: FacilityBed, initialTab?: BedDetailTab) => void;
  onStartAdmission: (bed: FacilityBed) => void;
  roomView: RoomView;
}): React.ReactElement {
  const availableCount = roomView.beds.filter((bed) => bed.status === "available").length;
  const maintenanceCount = roomView.beds.filter((bed) => bed.status === "maintenance").length;

  return (
    <article className="rounded-lg border border-kumo-line bg-kumo-base p-4">
      <header className="flex items-start justify-between gap-3">
        <div className="min-w-0">
          <h3 className="truncate text-sm font-semibold text-kumo-strong">{roomView.room.name}</h3>
          <p className="mt-1 text-xs text-muted-foreground">
            {roomView.room.code} · {roomView.room.occupiedBedCount}/{roomView.room.bedCount} 在住 · 容量 {roomView.room.capacity}
          </p>
        </div>
        <Badge variant={roomView.room.status === "active" ? "success" : "danger"}>
          {roomView.room.status === "active" ? "启用" : "停用"}
        </Badge>
      </header>

      <div className="mt-4 grid grid-cols-2 gap-2 sm:grid-cols-3">
        {roomView.beds.map((bed) => (
          <BedTile
            bed={bed}
            context={bedContexts[bed.id]}
            key={bed.id}
            onSelect={() => onSelectBed(bed)}
            onStartAdmission={() => onStartAdmission(bed)}
          />
        ))}
        {roomView.beds.length === 0 ? (
          <p className="col-span-full rounded-md border border-dashed px-3 py-5 text-center text-xs text-muted-foreground">暂无床位</p>
        ) : null}
      </div>

      <footer className="mt-4 flex flex-wrap gap-2 text-xs text-muted-foreground">
        <span>{availableCount} 空闲</span>
        <span>{maintenanceCount} 维修</span>
      </footer>
    </article>
  );
}

function BedTile({
  bed,
  context,
  onSelect,
  onStartAdmission,
}: {
  bed: FacilityBed;
  context: BedOperationalContext | undefined;
  onSelect: () => void;
  onStartAdmission: () => void;
}): React.ReactElement {
  const occupantName = context?.occupant?.elderName ?? bed.currentElderName;
  const bedActionLabel = bed.status === "available" ? "可办理入住" : bedStatusLabels[bed.status];

  return (
    <button
      className={cn(
        "grid min-h-28 content-between rounded-md border p-3 text-left transition focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-primary",
        bedTileClass(bed.status),
      )}
      onClick={bed.status === "available" ? onStartAdmission : onSelect}
      type="button"
    >
      <span className="flex items-start justify-between gap-2">
        <span className="min-w-0">
          <span className="block truncate text-sm font-semibold">{bed.code}</span>
          <span className="mt-1 block text-xs opacity-75">{bedStatusLabels[bed.status]}</span>
        </span>
        <span className={cn("mt-1 size-2 shrink-0 rounded-full", statusDotClass(bed.status))} aria-hidden="true" />
      </span>
      <span className="min-w-0">
        <span className="block truncate text-xs font-medium">{occupantName ?? bedActionLabel}</span>
        <span className="mt-1 block truncate text-[11px] opacity-75">{bed.notes || "无备注"}</span>
      </span>
    </button>
  );
}

function BedDetailDialog({
  activeAdmission,
  activeTab,
  admissions,
  bed,
  bedOptions,
  canManageAdmissions,
  context,
  dischargeNotes,
  elderOptions,
  isPending,
  notes,
  onClose,
  onDischargeNotesChange,
  onElderChange,
  onNotesChange,
  onSubmitAdmission,
  onSubmitDischarge,
  onSubmitTransfer,
  onTabChange,
  onTransferBedChange,
  onTransferNotesChange,
  selectedElderId,
  selectedTransferBedId,
  transferNotes,
}: {
  activeAdmission: Admission | undefined;
  activeTab: BedDetailTab;
  admissions: Admission[];
  bed: FacilityBed | undefined;
  bedOptions: SelectOption[];
  canManageAdmissions: boolean;
  context: BedOperationalContext | undefined;
  dischargeNotes: string;
  elderOptions: SelectOption[];
  isPending: boolean;
  notes: string;
  onClose: () => void;
  onDischargeNotesChange: (value: string) => void;
  onElderChange: (value: string) => void;
  onNotesChange: (value: string) => void;
  onSubmitAdmission: (event: FormEvent<HTMLFormElement>, bed: FacilityBed) => Promise<void>;
  onSubmitDischarge: (event: FormEvent<HTMLFormElement>, admission: Admission) => Promise<void>;
  onSubmitTransfer: (event: FormEvent<HTMLFormElement>, admission: Admission) => Promise<void>;
  onTabChange: (value: BedDetailTab) => void;
  onTransferBedChange: (value: string) => void;
  onTransferNotesChange: (value: string) => void;
  selectedElderId: string;
  selectedTransferBedId: string;
  transferNotes: string;
}): React.ReactElement {
  const title = bed ? `${bed.roomName} · ${bed.code}` : "床位详情";
  const description = bed ? `${bedStatusLabels[bed.status]} · ${bed.notes || "无备注"}` : undefined;

  return (
    <Dialog description={description} onClose={onClose} open={Boolean(bed)} title={title} width="wide">
      {bed ? (
        <div className="grid gap-5">
          <div className="flex flex-wrap gap-2" role="tablist" aria-label="床位详情">
            {bedDetailTabs.map((tab) => (
              <Button
                aria-selected={activeTab === tab.value}
                key={tab.value}
                onClick={() => onTabChange(tab.value)}
                role="tab"
                size="sm"
                type="button"
                variant={activeTab === tab.value ? "default" : "outline"}
              >
                {tab.label}
              </Button>
            ))}
          </div>

          {activeTab === "context" ? <BedContextPanel bed={bed} context={context} /> : null}
          {activeTab === "records" ? <AdmissionRecords admissions={admissions} /> : null}
          {activeTab === "actions" ? (
            <BedActionsPanel
              activeAdmission={activeAdmission}
              bed={bed}
              bedOptions={bedOptions}
              canManageAdmissions={canManageAdmissions}
              dischargeNotes={dischargeNotes}
              elderOptions={elderOptions}
              isPending={isPending}
              notes={notes}
              onDischargeNotesChange={onDischargeNotesChange}
              onElderChange={onElderChange}
              onNotesChange={onNotesChange}
              onSubmitAdmission={onSubmitAdmission}
              onSubmitDischarge={onSubmitDischarge}
              onSubmitTransfer={onSubmitTransfer}
              onTransferBedChange={onTransferBedChange}
              onTransferNotesChange={onTransferNotesChange}
              selectedElderId={selectedElderId}
              selectedTransferBedId={selectedTransferBedId}
              transferNotes={transferNotes}
            />
          ) : null}
        </div>
      ) : null}
    </Dialog>
  );
}

function BedContextPanel({
  bed,
  context,
}: {
  bed: FacilityBed;
  context: BedOperationalContext | undefined;
}): React.ReactElement {
  return (
    <div className="grid gap-4 lg:grid-cols-[18rem_minmax(0,1fr)]">
      <section className="rounded-lg border border-kumo-line p-4">
        <p className="text-xs text-muted-foreground">当前老人</p>
        <div className="mt-3">
          <OccupantSummary context={context} fallbackName={bed.currentElderName} />
        </div>
        <dl className="mt-4 grid gap-3 text-sm">
          <div>
            <dt className="text-xs text-muted-foreground">状态</dt>
            <dd className="mt-1">
              <Badge variant={bedBadgeVariant(bed.status)}>{bedStatusLabels[bed.status]}</Badge>
            </dd>
          </div>
          <div>
            <dt className="text-xs text-muted-foreground">备注</dt>
            <dd className="mt-1 text-kumo-strong">{bed.notes || "-"}</dd>
          </div>
        </dl>
      </section>

      <section className="rounded-lg border border-kumo-line p-4">
        <h3 className="text-sm font-semibold text-kumo-strong">运营上下文</h3>
        <div className="mt-3">
          <ContextLines lines={context?.lines ?? []} expanded />
        </div>
      </section>
    </div>
  );
}

function AdmissionRecords({ admissions }: { admissions: Admission[] }): React.ReactElement {
  return (
    <div className="overflow-x-auto rounded-md border">
      <Table className="w-full min-w-[720px] text-sm">
        <Table.Header className="bg-secondary text-left text-xs text-muted-foreground">
          <Table.Row>
            <Table.Head className="px-4 py-3 font-medium">老人</Table.Head>
            <Table.Head className="px-4 py-3 font-medium">状态</Table.Head>
            <Table.Head className="px-4 py-3 font-medium">入住时间</Table.Head>
            <Table.Head className="px-4 py-3 font-medium">结束时间</Table.Head>
            <Table.Head className="px-4 py-3 font-medium">备注</Table.Head>
          </Table.Row>
        </Table.Header>
        <Table.Body className="divide-y bg-card">
          {admissions.map((admission) => (
            <Table.Row key={admission.id}>
              <Table.Cell className="px-4 py-3 font-medium">{admission.elderName}</Table.Cell>
              <Table.Cell className="px-4 py-3">
                <Badge variant={admission.status === "active" ? "success" : "secondary"}>{admissionStatusLabels[admission.status]}</Badge>
              </Table.Cell>
              <Table.Cell className="px-4 py-3 text-muted-foreground">{formatDateTime(admission.admittedAt)}</Table.Cell>
              <Table.Cell className="px-4 py-3 text-muted-foreground">
                {admission.dischargedAt ? formatDateTime(admission.dischargedAt) : "-"}
              </Table.Cell>
              <Table.Cell className="px-4 py-3 text-muted-foreground">{admission.notes || "-"}</Table.Cell>
            </Table.Row>
          ))}
          {admissions.length === 0 ? (
            <Table.Row>
              <Table.Cell className="px-4 py-8 text-center text-muted-foreground" colSpan={5}>
                暂无该床位流水记录
              </Table.Cell>
            </Table.Row>
          ) : null}
        </Table.Body>
      </Table>
    </div>
  );
}

function BedActionsPanel({
  activeAdmission,
  bed,
  bedOptions,
  canManageAdmissions,
  dischargeNotes,
  elderOptions,
  isPending,
  notes,
  onDischargeNotesChange,
  onElderChange,
  onNotesChange,
  onSubmitAdmission,
  onSubmitDischarge,
  onSubmitTransfer,
  onTransferBedChange,
  onTransferNotesChange,
  selectedElderId,
  selectedTransferBedId,
  transferNotes,
}: {
  activeAdmission: Admission | undefined;
  bed: FacilityBed;
  bedOptions: SelectOption[];
  canManageAdmissions: boolean;
  dischargeNotes: string;
  elderOptions: SelectOption[];
  isPending: boolean;
  notes: string;
  onDischargeNotesChange: (value: string) => void;
  onElderChange: (value: string) => void;
  onNotesChange: (value: string) => void;
  onSubmitAdmission: (event: FormEvent<HTMLFormElement>, bed: FacilityBed) => Promise<void>;
  onSubmitDischarge: (event: FormEvent<HTMLFormElement>, admission: Admission) => Promise<void>;
  onSubmitTransfer: (event: FormEvent<HTMLFormElement>, admission: Admission) => Promise<void>;
  onTransferBedChange: (value: string) => void;
  onTransferNotesChange: (value: string) => void;
  selectedElderId: string;
  selectedTransferBedId: string;
  transferNotes: string;
}): React.ReactElement {
  if (bed.status === "available") {
    return (
      <form className="grid gap-3 rounded-lg border border-kumo-line p-4" onSubmit={(event) => void onSubmitAdmission(event, bed)}>
        <h3 className="text-sm font-semibold text-kumo-strong">办理入住</h3>
        <Select
          aria-label="入住老人"
          disabled={!canManageAdmissions || isPending}
          onValueChange={onElderChange}
          options={elderOptions}
          value={selectedElderId}
        />
        <Textarea
          aria-label="入住备注"
          disabled={!canManageAdmissions || isPending}
          onChange={(event) => onNotesChange(event.target.value)}
          placeholder="备注"
          value={notes}
        />
        <Button disabled={!canManageAdmissions || isPending} type="submit">
          <UserCheck className="size-4" aria-hidden="true" />
          办理入住
        </Button>
      </form>
    );
  }

  if (!activeAdmission) {
    return <p className="rounded-md border border-dashed px-4 py-8 text-center text-sm text-muted-foreground">该床位当前不能办理入住操作</p>;
  }

  return (
    <div className="grid gap-4 lg:grid-cols-2">
      <form className="grid gap-3 rounded-lg border border-kumo-line p-4" onSubmit={(event) => void onSubmitTransfer(event, activeAdmission)}>
        <h3 className="text-sm font-semibold text-kumo-strong">办理换床</h3>
        <p className="text-xs text-muted-foreground">
          当前：{activeAdmission.elderName} / {admissionBedLabel(activeAdmission)}
        </p>
        <Select
          aria-label="换床新床位"
          disabled={!canManageAdmissions || isPending}
          onValueChange={onTransferBedChange}
          options={bedOptions}
          value={selectedTransferBedId}
        />
        <Textarea
          aria-label="换床备注"
          disabled={!canManageAdmissions || isPending}
          onChange={(event) => onTransferNotesChange(event.target.value)}
          placeholder="备注"
          value={transferNotes}
        />
        <Button disabled={!canManageAdmissions || isPending} type="submit" variant="outline">
          <MoveRight className="size-4" aria-hidden="true" />
          办理换床
        </Button>
      </form>

      <form className="grid gap-3 rounded-lg border border-kumo-line p-4" onSubmit={(event) => void onSubmitDischarge(event, activeAdmission)}>
        <h3 className="text-sm font-semibold text-kumo-strong">办理退住</h3>
        <p className="text-xs text-muted-foreground">退住会关闭当前入住记录并释放该床位。</p>
        <Textarea
          aria-label="退住备注"
          disabled={!canManageAdmissions || isPending}
          onChange={(event) => onDischargeNotesChange(event.target.value)}
          placeholder="备注"
          value={dischargeNotes}
        />
        <Button disabled={!canManageAdmissions || isPending} type="submit" variant="destructive">
          <UserMinus className="size-4" aria-hidden="true" />
          办理退住
        </Button>
      </form>
    </div>
  );
}

function contextToneClass(tone: OperationalContextLine["tone"]): string {
  if (tone === "danger") {
    return "text-destructive";
  }
  if (tone === "warning") {
    return "text-amber-700";
  }
  return "text-muted-foreground";
}

function ContextLines({ expanded = false, lines }: { expanded?: boolean; lines: OperationalContextLine[] }): React.ReactElement {
  if (lines.length === 0) {
    return <span className="text-muted-foreground">-</span>;
  }

  return (
    <div className="grid gap-1">
      {lines.map((line) => (
        <p
          className={cn(expanded ? "text-sm" : "max-w-[260px] truncate text-xs", contextToneClass(line.tone))}
          key={`${line.kind}-${line.label}-${line.value}`}
        >
          <span className="font-medium">{contextKindLabels[line.kind]} · {line.label}</span> {line.value}
        </p>
      ))}
    </div>
  );
}

function OccupantSummary({
  context,
  fallbackName,
}: {
  context: BedOperationalContext | undefined;
  fallbackName: string | undefined;
}): React.ReactElement {
  if (!context?.occupant) {
    return <span className="text-muted-foreground">{fallbackName ?? "-"}</span>;
  }

  return (
    <div>
      <p className="font-medium">{context.occupant.elderName}</p>
      <p className="text-xs text-muted-foreground">
        {context.occupant.careLevel} / {context.occupant.status}
      </p>
    </div>
  );
}
