const { useEffect, useMemo, useRef, useState } = React;

const STORAGE_KEY = "parrot-pulse-react-state";
const MAX_PARROTS = 2;
const SPECIES_RANGES = {
  "虎皮鹦鹉": { min: 30, max: 40 },
  "牡丹鹦鹉": { min: 40, max: 60 },
  "玄凤鹦鹉": { min: 80, max: 120 },
  "和尚鹦鹉": { min: 90, max: 140 },
  "太平洋鹦鹉": { min: 24, max: 32 },
  "塞内加尔鹦鹉": { min: 120, max: 170 },
  "非洲灰鹦鹉": { min: 380, max: 520 },
  "亚马逊鹦鹉": { min: 300, max: 500 },
  "金太阳锥尾鹦鹉": { min: 95, max: 130 },
  "葵花凤头鹦鹉": { min: 500, max: 900 },
  "金刚鹦鹉": { min: 900, max: 1500 },
};

function getTodayString() {
  const today = new Date();
  const offset = today.getTimezoneOffset() * 60 * 1000;
  return new Date(today.getTime() - offset).toISOString().slice(0, 10);
}

function generateId(prefix) {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
}

function loadState() {
  const raw = localStorage.getItem(STORAGE_KEY);

  if (!raw) {
    const firstId = generateId("parrot");
    return {
      parrots: [
        {
          id: firstId,
          name: "Kiwi",
          species: "虎皮鹦鹉",
          birthday: "",
          sex: "",
          photo: "",
        },
      ],
      activeParrotId: firstId,
      records: [],
    };
  }

  try {
    const parsed = JSON.parse(raw);
    if (!parsed.parrots?.length) {
      throw new Error("invalid state");
    }
    return parsed;
  } catch {
    localStorage.removeItem(STORAGE_KEY);
    return loadState();
  }
}

function saveState(nextState) {
  try {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(nextState));
    return { ok: true };
  } catch (error) {
    return {
      ok: false,
      message: "保存失败，可能是上传图片过大。可以换一张更小的照片，或先导出 JSON 备份后再继续。",
    };
  }
}

function formatDate(dateString) {
  return new Intl.DateTimeFormat("zh-CN", {
    month: "short",
    day: "numeric",
    weekday: "short",
  }).format(new Date(dateString));
}

function rangeText(species) {
  const range = SPECIES_RANGES[species];
  return range ? `${range.min}-${range.max}g` : "暂无内置参考";
}

function evaluateWeight(species, weight) {
  const range = SPECIES_RANGES[species];
  const numericWeight = Number(weight);

  if (!range || !weight || Number.isNaN(numericWeight)) {
    return null;
  }

  if (numericWeight < range.min) {
    return {
      tone: "alert",
      short: "低于参考区间",
      message: `当前体重低于 ${species} 常见参考区间 ${range.min}-${range.max}g，建议结合食欲、精神和排便继续观察。`,
    };
  }

  if (numericWeight > range.max) {
    return {
      tone: "alert",
      short: "高于参考区间",
      message: `当前体重高于 ${species} 常见参考区间 ${range.min}-${range.max}g，可以留意近期饮食、活动量和体态变化。`,
    };
  }

  return {
    tone: "good",
    short: "落在参考区间",
    message: `当前体重落在 ${species} 常见参考区间 ${range.min}-${range.max}g 内。`,
  };
}

function buildAlerts(parrot, records) {
  if (!parrot) return [];

  const alerts = [];
  const sorted = [...records].sort((a, b) => b.date.localeCompare(a.date));
  const latest = sorted[0];

  if (!latest) {
    alerts.push({
      tone: "soft",
      title: "还没有健康记录",
      body: "先记下第一条体重和状态，异常提醒才会开始工作。",
    });
    return alerts;
  }

  const latestWeightStatus = evaluateWeight(parrot.species, latest.weight);
  if (latestWeightStatus && latestWeightStatus.tone === "alert") {
    alerts.push({
      tone: "alert",
      title: "最近体重超出常见区间",
      body: latestWeightStatus.message,
    });
  }

  if (sorted.length >= 3) {
    const lastThree = sorted.slice(0, 3).map((item) => Number(item.weight));
    if (lastThree[0] < lastThree[1] && lastThree[1] < lastThree[2]) {
      alerts.push({
        tone: "alert",
        title: "体重连续 3 次下降",
        body: "最近三条记录都在下降，建议结合食欲、精神状态和饮食变化重点观察。",
      });
    }
  }

  if (latest.appetite === "偏差" || latest.mood === "异常" || latest.droppings === "异常") {
    alerts.push({
      tone: "alert",
      title: "最近状态里有异常项",
      body: `最近一次记录包含 ${[
        latest.appetite === "偏差" ? "食欲偏差" : "",
        latest.mood === "异常" ? "精神异常" : "",
        latest.droppings === "异常" ? "排便异常" : "",
      ]
        .filter(Boolean)
        .join("、")}，建议持续复查。`,
    });
  }

  if (!alerts.length) {
    alerts.push({
      tone: "good",
      title: "最近状态比较稳定",
      body: "目前没有明显异常趋势，可以继续按天记录，帮助你更早发现变化。",
    });
  }

  return alerts;
}

function blobToDataUrl(blob) {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = () => resolve(String(reader.result || ""));
    reader.onerror = () => reject(new Error("读取图片失败"));
    reader.readAsDataURL(blob);
  });
}

function canvasToBlob(canvas, quality) {
  return new Promise((resolve, reject) => {
    canvas.toBlob(
      (blob) => {
        if (!blob) {
          reject(new Error("图片压缩失败"));
          return;
        }
        resolve(blob);
      },
      "image/jpeg",
      quality
    );
  });
}

function loadImageFromObjectUrl(url) {
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.onload = () => resolve(image);
    image.onerror = () => reject(new Error("这张图片暂时处理不了，建议换成 JPG 或 PNG 再试一次"));
    image.src = url;
  });
}

async function fileToDataUrl(file, options = {}) {
  if (!file) {
    return "";
  }

  if (!file.type.startsWith("image/")) {
    throw new Error("请选择图片文件");
  }

  if (file.size > 20 * 1024 * 1024) {
    throw new Error("图片太大了，建议先换一张 20MB 以内的照片");
  }

  const { maxSize = 768, quality = 0.72 } = options;
  const objectUrl = URL.createObjectURL(file);

  try {
    const image = await loadImageFromObjectUrl(objectUrl);
    const scale = Math.min(maxSize / image.width, maxSize / image.height, 1);
    const canvas = document.createElement("canvas");
    canvas.width = Math.max(1, Math.round(image.width * scale));
    canvas.height = Math.max(1, Math.round(image.height * scale));
    const context = canvas.getContext("2d");

    if (!context) {
      throw new Error("当前浏览器暂时不能处理这张图片");
    }

    context.drawImage(image, 0, 0, canvas.width, canvas.height);
    const blob = await canvasToBlob(canvas, quality);
    return await blobToDataUrl(blob);
  } finally {
    URL.revokeObjectURL(objectUrl);
  }
}

function downloadFile(filename, content, type) {
  const blob = new Blob([content], { type });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = filename;
  link.click();
  URL.revokeObjectURL(url);
}

function toCsvValue(value) {
  const text = String(value ?? "");
  const escaped = text.replace(/"/g, '""');
  return `"${escaped}"`;
}

function exportStateAsJson(state) {
  const content = JSON.stringify(state, null, 2);
  downloadFile("parrot-pulse-backup.json", content, "application/json;charset=utf-8");
}

function exportStateAsCsv(state) {
  const parrotMap = Object.fromEntries(state.parrots.map((parrot) => [parrot.id, parrot]));
  const header = [
    "parrotId",
    "parrotName",
    "species",
    "date",
    "weight",
    "appetite",
    "mood",
    "droppings",
    "notes",
    "hasPhoto",
  ];

  const rows = state.records
    .slice()
    .sort((a, b) => a.date.localeCompare(b.date))
    .map((record) => {
      const parrot = parrotMap[record.parrotId] || {};
      return [
        record.parrotId,
        parrot.name || "",
        parrot.species || "",
        record.date,
        record.weight,
        record.appetite,
        record.mood,
        record.droppings,
        record.notes || "",
        record.photo ? "yes" : "no",
      ]
        .map(toCsvValue)
        .join(",");
    });

  const content = [header.join(","), ...rows].join("\n");
  downloadFile("parrot-pulse-records.csv", content, "text/csv;charset=utf-8");
}

function WeightTrendChart({ records }) {
  if (records.length < 2) {
    return <div className="empty-state">至少记录 2 天体重后，这里会出现趋势折线图。</div>;
  }

  const ordered = [...records]
    .slice()
    .sort((a, b) => a.date.localeCompare(b.date))
    .slice(-7);
  const weights = ordered.map((record) => Number(record.weight));
  const min = Math.min(...weights);
  const max = Math.max(...weights);
  const range = Math.max(max - min, 1);
  const width = 320;
  const height = 160;
  const padding = 16;

  const points = ordered.map((record, index) => {
    const x = padding + (index * (width - padding * 2)) / Math.max(ordered.length - 1, 1);
    const y = height - padding - ((Number(record.weight) - min) / range) * (height - padding * 2);
    return {
      x,
      y,
      weight: record.weight,
      date: record.date,
    };
  });

  const path = points.map((point, index) => `${index === 0 ? "M" : "L"} ${point.x} ${point.y}`).join(" ");

  return (
    <div className="trend-chart-wrap">
      <svg viewBox={`0 0 ${width} ${height}`} className="trend-chart" role="img" aria-label="体重趋势折线图">
        <defs>
          <linearGradient id="trendLine" x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" stopColor="#f28f3b" />
            <stop offset="100%" stopColor="#6b9c59" />
          </linearGradient>
        </defs>
        {[0, 1, 2, 3].map((step) => {
          const y = padding + (step * (height - padding * 2)) / 3;
          return <line key={step} x1={padding} y1={y} x2={width - padding} y2={y} className="trend-grid-line" />;
        })}
        <path d={path} fill="none" stroke="url(#trendLine)" strokeWidth="4" strokeLinecap="round" />
        {points.map((point) => (
          <g key={point.date}>
            <circle cx={point.x} cy={point.y} r="5" className="trend-point" />
            <text x={point.x} y={point.y - 10} textAnchor="middle" className="trend-point-label">
              {point.weight}g
            </text>
          </g>
        ))}
      </svg>
      <div className="trend-axis">
        {ordered.map((record) => (
          <span key={record.date}>{record.date.slice(5)}</span>
        ))}
      </div>
    </div>
  );
}

function MobileShell({ children }) {
  return (
    <div className="mobile-shell">
      <div className="mobile-device">
        <div className="device-topbar">
          <span>9:41</span>
          <span>Parrot Pulse</span>
          <span>100%</span>
        </div>
        {children}
      </div>
    </div>
  );
}

function App() {
  const [state, setState] = useState(loadState);
  const [profileDraft, setProfileDraft] = useState({
    name: "",
    species: "虎皮鹦鹉",
    birthday: "",
    sex: "",
    photo: "",
  });
  const [recordDraft, setRecordDraft] = useState({
    date: getTodayString(),
    weight: "",
    appetite: "很好",
    mood: "活跃",
    droppings: "正常",
    notes: "",
    photo: "",
  });
  const [saveMessage, setSaveMessage] = useState("");
  const [saveTone, setSaveTone] = useState("good");
  const [uploadingTarget, setUploadingTarget] = useState("");
  const profilePhotoRef = useRef(null);
  const recordPhotoRef = useRef(null);

  const activeParrot = useMemo(
    () => state.parrots.find((parrot) => parrot.id === state.activeParrotId) || state.parrots[0],
    [state]
  );

  const activeRecords = useMemo(
    () =>
      state.records
        .filter((record) => record.parrotId === activeParrot?.id)
        .sort((a, b) => b.date.localeCompare(a.date)),
    [state.records, activeParrot]
  );

  const weightStatus = useMemo(
    () => evaluateWeight(profileDraft.species, recordDraft.weight),
    [profileDraft.species, recordDraft.weight]
  );

  const alerts = useMemo(
    () => buildAlerts(activeParrot, activeRecords),
    [activeParrot, activeRecords]
  );

  useEffect(() => {
    if (!activeParrot) return;
    setProfileDraft({
      name: activeParrot.name || "",
      species: activeParrot.species || "虎皮鹦鹉",
      birthday: activeParrot.birthday || "",
      sex: activeParrot.sex || "",
      photo: activeParrot.photo || "",
    });
  }, [activeParrot]);

  useEffect(() => {
    const result = saveState(state);
    if (!result.ok) {
      setSaveTone("alert");
      setSaveMessage(result.message);
    }
  }, [state]);

  useEffect(() => {
    if ("serviceWorker" in navigator && window.location.protocol !== "file:") {
      navigator.serviceWorker.register("./service-worker.js").catch(() => {});
    }
  }, []);

  const addSecondParrot = () => {
    if (state.parrots.length >= MAX_PARROTS) return;

    const id = generateId("parrot");
    const nextParrot = {
      id,
      name: `Parrot ${state.parrots.length + 1}`,
      species: "玄凤鹦鹉",
      birthday: "",
      sex: "",
      photo: "",
    };

    setState((current) => ({
      ...current,
      parrots: [...current.parrots, nextParrot],
      activeParrotId: id,
    }));
  };

  const saveProfileDraft = () => {
    if (!activeParrot) return;

    setState((current) => ({
      ...current,
      parrots: current.parrots.map((parrot) =>
        parrot.id === activeParrot.id ? { ...parrot, ...profileDraft } : parrot
      ),
    }));
    setSaveTone("good");
    setSaveMessage("档案已保存。");
  };

  const saveRecordDraft = () => {
    if (!recordDraft.weight || !activeParrot) return;

    const nextRecord = {
      id: generateId("record"),
      parrotId: activeParrot.id,
      ...recordDraft,
    };

    setState((current) => {
      const rest = current.records.filter(
        (record) => !(record.parrotId === activeParrot.id && record.date === recordDraft.date)
      );
      return {
        ...current,
        records: [...rest, nextRecord],
      };
    });

    setRecordDraft({
      date: getTodayString(),
      weight: "",
      appetite: "很好",
      mood: "活跃",
      droppings: "正常",
      notes: "",
      photo: "",
    });

    if (recordPhotoRef.current) {
      recordPhotoRef.current.value = "";
    }

    setSaveTone("good");
    setSaveMessage("健康记录已保存。");
  };

  const handleProfilePhotoChange = async (event) => {
    const file = event.target.files?.[0];
    if (!file) return;

    try {
      setUploadingTarget("profile");
      setSaveTone("soft");
      setSaveMessage("正在处理头像图片...");
      const photo = await fileToDataUrl(file, { maxSize: 640, quality: 0.68 });
      setProfileDraft((current) => ({ ...current, photo }));
      setSaveTone("good");
      setSaveMessage("头像已处理完成，记得点“保存当前鹦鹉档案”。");
    } catch (error) {
      setSaveTone("alert");
      setSaveMessage(error.message || "头像上传失败，请换一张更小的图片再试一次。");
    } finally {
      setUploadingTarget("");
      event.target.value = "";
    }
  };

  const handleRecordPhotoChange = async (event) => {
    const file = event.target.files?.[0];
    if (!file) return;

    try {
      setUploadingTarget("record");
      setSaveTone("soft");
      setSaveMessage("正在处理记录照片...");
      const photo = await fileToDataUrl(file, { maxSize: 960, quality: 0.72 });
      setRecordDraft((current) => ({ ...current, photo }));
      setSaveTone("good");
      setSaveMessage("记录照片已处理完成，记得点“保存今天的记录”。");
    } catch (error) {
      setSaveTone("alert");
      setSaveMessage(error.message || "记录照片上传失败，请换一张更小的图片再试一次。");
    } finally {
      setUploadingTarget("");
      event.target.value = "";
    }
  };

  const latestRecord = activeRecords[0];
  const latestWeightStatus = latestRecord
    ? evaluateWeight(activeParrot?.species, latestRecord.weight)
    : null;

  return (
    <MobileShell>
      <div className="app-screen">
        <header className="hero-card">
          <div>
            <p className="eyebrow">Parrot Health Tracker</p>
            <h1>
              <span>育鹦书</span>
              <span>更好记录鸟宝日常</span>
            </h1>
            <p className="hero-text">
              最多支持 2 只鹦鹉，记录体重、照片和日常状态，用轻提醒看见异常变化。
            </p>
          </div>
          <div className="hero-badge-stack">
            <div className="hero-badge">
              <strong>{activeParrot?.name || "--"}</strong>
              <span>{activeParrot?.species || "未选择品种"}</span>
            </div>
            <div className="hero-badge">
              <strong>{latestRecord ? `${latestRecord.weight}g` : "--"}</strong>
              <span>{latestWeightStatus?.short || "最近体重"}</span>
            </div>
          </div>
        </header>

        <section className="section-card">
          <div className="section-head">
            <div>
              <p className="section-kicker">Parrots</p>
              <h2>鹦鹉切换</h2>
            </div>
            <button
              type="button"
              className="ghost-button"
              onClick={addSecondParrot}
              disabled={state.parrots.length >= MAX_PARROTS}
            >
              {state.parrots.length >= MAX_PARROTS ? "最多 2 只" : "+ 添加第二只"}
            </button>
          </div>

          <div className="parrot-switcher">
            {state.parrots.map((parrot) => (
              <button
                key={parrot.id}
                type="button"
                className={`parrot-chip ${parrot.id === activeParrot?.id ? "is-active" : ""}`}
                onClick={() => setState((current) => ({ ...current, activeParrotId: parrot.id }))}
              >
                <span className="chip-avatar">
                  {parrot.photo ? <img src={parrot.photo} alt={parrot.name} /> : parrot.name.slice(0, 1)}
                </span>
                <span>
                  <strong>{parrot.name}</strong>
                  <small>{parrot.species}</small>
                </span>
              </button>
            ))}
          </div>
        </section>

        <section className="summary-grid">
          <article className="metric-card">
            <span>常见参考</span>
            <strong>{rangeText(activeParrot?.species)}</strong>
          </article>
          <article className="metric-card">
            <span>累计记录</span>
            <strong>{activeRecords.length} 天</strong>
          </article>
          <article className="metric-card">
            <span>最近状态</span>
            <strong>{latestRecord?.mood || "--"}</strong>
          </article>
          <article className="metric-card">
            <span>照片记录</span>
            <strong>{activeRecords.filter((record) => record.photo).length} 张</strong>
          </article>
        </section>

        {saveMessage ? (
          <section className={`section-card save-feedback tone-${saveTone}`}>
            <strong>{saveTone === "good" ? "保存状态正常" : "保存遇到问题"}</strong>
            <p>{saveMessage}</p>
          </section>
        ) : null}

        <section className="section-card">
          <div className="section-head">
            <div>
              <p className="section-kicker">Trend</p>
              <h2>体重趋势折线图</h2>
            </div>
          </div>
          <WeightTrendChart records={activeRecords} />
        </section>

        <section className="section-card">
          <div className="section-head">
            <div>
              <p className="section-kicker">Alerts</p>
              <h2>异常提醒</h2>
            </div>
          </div>
          <div className="alert-list">
            {alerts.map((alert, index) => (
              <article key={`${alert.title}-${index}`} className={`alert-card tone-${alert.tone}`}>
                <strong>{alert.title}</strong>
                <p>{alert.body}</p>
              </article>
            ))}
          </div>
        </section>

        <section className="section-card">
          <div className="section-head">
            <div>
              <p className="section-kicker">Profile</p>
              <h2>当前鹦鹉档案</h2>
            </div>
          </div>

          <div className="form-stack">
            <div className="photo-picker">
              <div className="photo-preview large">
                {profileDraft.photo ? (
                  <img src={profileDraft.photo} alt={profileDraft.name || "鹦鹉头像"} />
                ) : (
                  <span>{profileDraft.name ? profileDraft.name.slice(0, 1) : "?"}</span>
                )}
              </div>
              <div className="photo-actions">
                <button type="button" className="ghost-button" onClick={() => profilePhotoRef.current?.click()}>
                  {uploadingTarget === "profile" ? "正在处理..." : "上传头像"}
                </button>
                <input
                  ref={profilePhotoRef}
                  type="file"
                  accept="image/*"
                  hidden
                  onChange={handleProfilePhotoChange}
                />
                <span>建议用 JPG 或 PNG，系统会自动压缩大图。</span>
              </div>
            </div>

            <div className="field-grid">
              <label>
                名字
                <input
                  value={profileDraft.name}
                  onChange={(event) => setProfileDraft((current) => ({ ...current, name: event.target.value }))}
                  placeholder="比如 Kiwi"
                />
              </label>
              <label>
                品种
                <select
                  value={profileDraft.species}
                  onChange={(event) => setProfileDraft((current) => ({ ...current, species: event.target.value }))}
                >
                  {Object.keys(SPECIES_RANGES).map((species) => (
                    <option key={species} value={species}>
                      {species}
                    </option>
                  ))}
                </select>
              </label>
              <label>
                生日
                <input
                  type="date"
                  value={profileDraft.birthday}
                  onChange={(event) =>
                    setProfileDraft((current) => ({ ...current, birthday: event.target.value }))
                  }
                />
              </label>
              <label>
                性别
                <select
                  value={profileDraft.sex}
                  onChange={(event) => setProfileDraft((current) => ({ ...current, sex: event.target.value }))}
                >
                  <option value="">未填写</option>
                  <option value="公">公</option>
                  <option value="母">母</option>
                  <option value="未知">未知</option>
                </select>
              </label>
            </div>

            <div className="inline-note">
              <strong>{profileDraft.species}</strong> 的常见体重参考区间是{" "}
              <strong>{rangeText(profileDraft.species)}</strong>，这里作为日常记录参考，不替代诊疗判断。
            </div>

            <button type="button" className="primary-button" onClick={saveProfileDraft}>
              保存当前鹦鹉档案
            </button>
          </div>
        </section>

        <section className="section-card">
          <div className="section-head">
            <div>
              <p className="section-kicker">Daily Log</p>
              <h2>新增健康记录</h2>
            </div>
          </div>

          <div className="form-stack">
            <div className="field-grid">
              <label>
                日期
                <input
                  type="date"
                  value={recordDraft.date}
                  onChange={(event) => setRecordDraft((current) => ({ ...current, date: event.target.value }))}
                />
              </label>
              <label>
                体重（g）
                <input
                  type="number"
                  min="1"
                  step="0.1"
                  value={recordDraft.weight}
                  onChange={(event) => setRecordDraft((current) => ({ ...current, weight: event.target.value }))}
                  placeholder="35.4"
                />
              </label>
              <label>
                食欲
                <select
                  value={recordDraft.appetite}
                  onChange={(event) =>
                    setRecordDraft((current) => ({ ...current, appetite: event.target.value }))
                  }
                >
                  <option value="很好">很好</option>
                  <option value="正常">正常</option>
                  <option value="一般">一般</option>
                  <option value="偏差">偏差</option>
                </select>
              </label>
              <label>
                精神
                <select
                  value={recordDraft.mood}
                  onChange={(event) => setRecordDraft((current) => ({ ...current, mood: event.target.value }))}
                >
                  <option value="活跃">活跃</option>
                  <option value="正常">正常</option>
                  <option value="安静">安静</option>
                  <option value="异常">异常</option>
                </select>
              </label>
              <label>
                排便
                <select
                  value={recordDraft.droppings}
                  onChange={(event) =>
                    setRecordDraft((current) => ({ ...current, droppings: event.target.value }))
                  }
                >
                  <option value="正常">正常</option>
                  <option value="偏稀">偏稀</option>
                  <option value="偏干">偏干</option>
                  <option value="异常">异常</option>
                </select>
              </label>
            </div>

            <div className={`inline-note ${weightStatus ? `tone-${weightStatus.tone}` : ""}`}>
              {recordDraft.weight
                ? weightStatus?.message || `当前品种还没有内置参考区间。`
                : `${profileDraft.species} 的常见体重参考区间：${rangeText(profileDraft.species)}`}
            </div>

            <label>
              备注
              <textarea
                rows="4"
                value={recordDraft.notes}
                onChange={(event) => setRecordDraft((current) => ({ ...current, notes: event.target.value }))}
                placeholder="比如：换粮、洗澡、掉毛、看医生、叫声变少"
              />
            </label>

            <div className="photo-picker">
              <div className="photo-preview record">
                {recordDraft.photo ? <img src={recordDraft.photo} alt="健康记录照片" /> : <span>+</span>}
              </div>
              <div className="photo-actions">
                <button type="button" className="ghost-button" onClick={() => recordPhotoRef.current?.click()}>
                  {uploadingTarget === "record" ? "正在处理..." : "上传记录照片"}
                </button>
                <input
                  ref={recordPhotoRef}
                  type="file"
                  accept="image/*"
                  hidden
                  onChange={handleRecordPhotoChange}
                />
                <span>大图会自动压缩，方便手机端保存。</span>
              </div>
            </div>

            <button type="button" className="primary-button" onClick={saveRecordDraft}>
              保存今天的记录
            </button>
          </div>
        </section>

        <section className="section-card">
          <div className="section-head">
            <div>
              <p className="section-kicker">History</p>
              <h2>最近记录</h2>
            </div>
          </div>

          <div className="record-list">
            {activeRecords.length ? (
              activeRecords.map((record) => {
                const status = evaluateWeight(activeParrot.species, record.weight);
                return (
                  <article key={record.id} className="record-card">
                    <div className="record-top">
                      <div>
                        <strong>{formatDate(record.date)}</strong>
                        <span>{record.weight} g</span>
                      </div>
                      <span className={`pill ${status?.tone === "alert" ? "pill-alert" : "pill-good"}`}>
                        {status?.short || "已记录"}
                      </span>
                    </div>
                    <div className="tag-row">
                      <span className="tag">食欲：{record.appetite}</span>
                      <span className="tag">精神：{record.mood}</span>
                      <span className="tag">排便：{record.droppings}</span>
                    </div>
                    {record.photo ? (
                      <img className="record-image" src={record.photo} alt={`${activeParrot.name} 的记录照片`} />
                    ) : null}
                    <p className="record-notes">{record.notes || "今天没有额外备注。"}</p>
                  </article>
                );
              })
            ) : (
              <div className="empty-state">还没有记录，先为 {activeParrot?.name || "这只鹦鹉"} 添加第一条健康日志。</div>
            )}
          </div>
        </section>

        <section className="section-card install-tip">
          <div className="section-head">
            <div>
              <p className="section-kicker">Backup</p>
              <h2>导出与备份</h2>
            </div>
          </div>
          <div className="backup-actions">
            <button type="button" className="primary-button" onClick={() => exportStateAsJson(state)}>
              导出 JSON
            </button>
            <button type="button" className="ghost-button" onClick={() => exportStateAsCsv(state)}>
              导出 CSV
            </button>
          </div>
          <p>
            `JSON` 适合完整备份和之后恢复，`CSV` 适合拿去表格里继续整理。导出内容包含最多 2 只鹦鹉档案和全部历史记录。
          </p>
        </section>

        <section className="section-card install-tip">
          <div className="section-head">
            <div>
              <p className="section-kicker">PWA</p>
              <h2>安装与离线体验</h2>
            </div>
          </div>
          <p>
            这个版本已经带上 `manifest` 和 `service worker`。如果你现在是通过 `file://` 打开，浏览器通常不会启用完整
            PWA 能力；用本地服务器打开后，会更像手机 App，也能更稳定地离线使用。
          </p>
        </section>
      </div>
    </MobileShell>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
