"use client";

import { useEffect, useRef, useState, useCallback, memo } from "react";
import { useTranslations } from "next-intl";
import {
  Chart as ChartJS,
  LineElement,
  PointElement,
  LinearScale,
  CategoryScale,
  Title,
  Tooltip,
  Legend,
  Filler,
} from "chart.js";
import { Line } from "react-chartjs-2";
import Card from "@mui/material/Card";
import CardContent from "@mui/material/CardContent";
import Typography from "@mui/material/Typography";
import Box from "@mui/material/Box";
import Grid from "@mui/material/Grid2";
import Button from "@mui/material/Button";

ChartJS.register(
  LineElement,
  PointElement,
  LinearScale,
  CategoryScale,
  Title,
  Tooltip,
  Legend,
  Filler,
);

// ─── Types ───────────────────────────────────────────────────────────────────

interface Leaf {
  id: number;
  side: "left" | "right";
  heightFraction: number;
  scale: number;
  swayOffset: number;
  length: number;
  branchId: number | null; // null = on main stem, number = on a branch
}

interface Branch {
  id: number;
  side: "left" | "right";
  heightFraction: number; // where on stem it starts (0..1)
  length: number; // branch length px
  angle: number; // base angle in degrees
  scale: number; // 0..1 grow-in
  swayOffset: number;
  thickness: number; // px
}

interface Fruit {
  id: number;
  branchId: number | null;
  leafId: number;
  side: "left" | "right";
  scale: number;
  swayOffset: number;
  color: string;
  size: number; // varied fruit radius
}

interface PlantState {
  height: number;
  leaves: Leaf[];
  branches: Branch[];
  fruits: Fruit[];
  tick: number;
  yield: number;
  yieldRate: number;
}

interface EnvironmentSettings {
  light: number;
  water: number;
}

// ─── Constants ───────────────────────────────────────────────────────────────

const MAX_HEIGHT = 280;
const MAX_YIELD = 500;
const SVG_W = 280;
const SVG_H = 400;
const STEM_X = SVG_W / 2;
const BASE_Y = SVG_H - 24;
const LEAF_INTERVAL_PX = 30;
const MAX_LEAVES = 14;
const MAX_BRANCHES = 6;
const FRUIT_COLORS = [
  "#ef4444",
  "#f97316",
  "#eab308",
  "#f472b6",
  "#a855f7",
  "#22c55e",
];

// ─── Helper: compute growth speed multiplier from env settings ────────────────

function growthRate(env: EnvironmentSettings, speed: number): number {
  const lightFactor = 0.3 + (env.light / 100) * 0.7;
  const waterFactor = 0.3 + (env.water / 100) * 0.7;
  return speed * lightFactor * waterFactor;
}

// Yield rate in g/s: leaves and height progress amplify yield production
function computeYieldRate(
  env: EnvironmentSettings,
  leafCount: number,
  heightProgress: number,
): number {
  const lightFactor = 0.2 + (env.light / 100) * 0.8;
  const waterFactor = 0.2 + (env.water / 100) * 0.8;
  const leafFactor = leafCount / MAX_LEAVES;
  // yield only starts after 20% growth and accelerates with more leaves
  const maturityFactor = Math.max(0, (heightProgress - 0.2) / 0.8);
  return parseFloat(
    (
      MAX_YIELD *
      0.012 *
      lightFactor *
      waterFactor *
      leafFactor *
      maturityFactor
    ).toFixed(3),
  );
}

// ─── Helpers: quadratic bezier point / tangent at t ─────────────────────────

function qBez(p0: number, p1: number, p2: number, t: number) {
  return (1 - t) * (1 - t) * p0 + 2 * (1 - t) * t * p1 + t * t * p2;
}

function qBezTan(p0: number, p1: number, p2: number, t: number) {
  return 2 * (1 - t) * (p1 - p0) + 2 * t * (p2 - p1);
}

// ─── Plant SVG Component ──────────────────────────────────────────────────────

function PlantSVG({
  plant,
  tick,
  running,
}: {
  plant: PlantState;
  tick: number;
  running: boolean;
}) {
  const stemTop = BASE_Y - plant.height;
  const progress = plant.height / MAX_HEIGHT;
  const stemW = 6 + Math.min(progress * 7, 7);

  const sway = Math.sin(tick / 55) * 3;

  // Stem control points — quadratic Bezier
  const s0x = STEM_X,
    s0y = BASE_Y;
  const s1x = STEM_X + sway * 0.4,
    s1y = stemTop + plant.height * 0.5;
  const s2x = STEM_X + sway,
    s2y = stemTop;

  // Get point on main stem at fraction t (0=base, 1=top)
  const stemPt = (t: number) => ({
    x: qBez(s0x, s1x, s2x, t),
    y: qBez(s0y, s1y, s2y, t),
  });

  // Get angle on main stem at t
  const stemAngle = (t: number) => {
    const dx = qBezTan(s0x, s1x, s2x, t);
    const dy = qBezTan(s0y, s1y, s2y, t);
    return (Math.atan2(dy, dx) * 180) / Math.PI;
  };

  // Get branch tip position
  const branchTip = (b: Branch) => {
    const base = stemPt(b.heightFraction);
    const dir = b.side === "left" ? -1 : 1;
    const bSway = Math.sin(tick / 30 + b.swayOffset) * 4 * b.scale;
    const rad = ((b.angle + bSway) * Math.PI) / 180;
    const len = b.length * b.scale;
    return {
      bx: base.x,
      by: base.y,
      tx: base.x + Math.cos(rad) * len * dir,
      ty: base.y + Math.sin(rad) * len,
      cx: base.x + Math.cos(rad) * len * 0.5 * dir,
      cy: base.y + Math.sin(rad) * len * 0.35 - 8 * b.scale,
    };
  };

  return (
    <svg
      width={SVG_W}
      height={SVG_H}
      viewBox={`0 0 ${SVG_W} ${SVG_H}`}
      className="drop-shadow-2xl"
    >
      <defs>
        <linearGradient id="sg" x1="0" y1="1" x2="0" y2="0">
          <stop offset="0%" stopColor="#24462e" />
          <stop offset="50%" stopColor="#3d7a4f" />
          <stop offset="100%" stopColor="#6ab870" />
        </linearGradient>
        <linearGradient id="bg" x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor="#4a8c5a" />
          <stop offset="100%" stopColor="#2e5a38" />
        </linearGradient>
        <radialGradient id="soilG" cx="50%" cy="40%" r="60%">
          <stop offset="0%" stopColor="#b08030" />
          <stop offset="100%" stopColor="#4a2c0a" />
        </radialGradient>
        <filter id="fglow" x="-50%" y="-50%" width="200%" height="200%">
          <feGaussianBlur stdDeviation="2" result="b" />
          <feMerge>
            <feMergeNode in="b" />
            <feMergeNode in="SourceGraphic" />
          </feMerge>
        </filter>
        <filter id="lsh" x="-30%" y="-30%" width="160%" height="160%">
          <feDropShadow
            dx="0.8"
            dy="1.2"
            stdDeviation="1.2"
            floodColor="#0a2010"
            floodOpacity="0.35"
          />
        </filter>
      </defs>

      {/* ── Floating pollen particles ── */}
      {running &&
        progress > 0.35 &&
        [0, 1, 2, 3, 4, 5].map((i) => {
          const px = STEM_X + Math.sin(tick / 28 + i * 1.1) * 40;
          const cycle = (tick * 0.35 + i * 30) % 80;
          const py = stemTop - 12 - cycle;
          return (
            <circle
              key={`p${i}`}
              cx={px}
              cy={py}
              r={1.4}
              fill="#fde68a"
              opacity={Math.max(0, 0.55 - cycle / 160)}
            />
          );
        })}

      {/* ── Soil mound ── */}
      <ellipse
        cx={STEM_X}
        cy={BASE_Y + 8}
        rx={58}
        ry={14}
        fill="url(#soilG)"
        opacity={0.9}
      />
      {[-24, -10, 4, 16, 28].map((dx) => (
        <line
          key={dx}
          x1={STEM_X + dx}
          y1={BASE_Y + 5}
          x2={STEM_X + dx + 5}
          y2={BASE_Y + 10}
          stroke="#2a1400"
          strokeWidth={0.8}
          opacity={0.35}
        />
      ))}
      {/* Small grass tufts */}
      {[-30, -14, 18, 32].map((dx, i) => (
        <path
          key={`grass${i}`}
          d={`M${STEM_X + dx} ${BASE_Y + 3} q${2} ${-6} ${0} ${-10} M${STEM_X + dx + 3} ${BASE_Y + 3} q${-1} ${-5} ${1} ${-8}`}
          stroke="#5a9a5a"
          strokeWidth={0.8}
          fill="none"
          opacity={0.4}
        />
      ))}

      {/* ── Roots ── */}
      {plant.height > 15 && (
        <g opacity={0.4 + progress * 0.15}>
          {[
            { dx: -22, dy: 22, w: 2.2, cx: -10, cy: 8 },
            { dx: 18, dy: 20, w: 1.8, cx: 8, cy: 10 },
            { dx: -8, dy: 24, w: 1.2, cx: -4, cy: 12 },
            { dx: 12, dy: 18, w: 1, cx: 6, cy: 14 },
          ].map((r, i) => (
            <path
              key={`root${i}`}
              d={`M${STEM_X} ${BASE_Y} Q${STEM_X + r.cx} ${BASE_Y + r.cy} ${STEM_X + r.dx} ${BASE_Y + r.dy}`}
              stroke="#3b2a12"
              strokeWidth={r.w}
              fill="none"
              strokeLinecap="round"
            />
          ))}
        </g>
      )}

      {/* ── Main stem (quadratic bezier) ── */}
      {plant.height > 0 && (
        <>
          <path
            d={`M${s0x} ${s0y} Q${s1x} ${s1y} ${s2x} ${s2y}`}
            stroke="url(#sg)"
            strokeWidth={stemW}
            fill="none"
            strokeLinecap="round"
          />
          {/* Stem highlight vein */}
          <path
            d={`M${s0x + 1.5} ${s0y - 6} Q${s1x + 1.5} ${s1y} ${s2x + 1.5} ${s2y + 6}`}
            stroke="rgba(160,220,140,0.2)"
            strokeWidth={1.8}
            fill="none"
            strokeLinecap="round"
          />
          {/* Stem node bumps — small circles at branch attachment points */}
          {plant.branches.map((b) => {
            const pt = stemPt(b.heightFraction);
            return (
              <circle
                key={`node${b.id}`}
                cx={pt.x}
                cy={pt.y}
                r={stemW * 0.5 + 1}
                fill="#3a6a42"
                opacity={b.scale * 0.6}
              />
            );
          })}
        </>
      )}

      {/* ── Branches (curved) ── */}
      {plant.branches.map((b) => {
        const { bx, by, tx, ty, cx, cy } = branchTip(b);
        const bw = b.thickness * b.scale;
        return (
          <g key={`br${b.id}`} opacity={b.scale}>
            <path
              d={`M${bx} ${by} Q${cx} ${cy} ${tx} ${ty}`}
              stroke="url(#bg)"
              strokeWidth={bw}
              fill="none"
              strokeLinecap="round"
            />
            {/* branch highlight */}
            <path
              d={`M${bx} ${by} Q${cx - 0.5} ${cy - 0.5} ${tx} ${ty}`}
              stroke="rgba(150,210,130,0.15)"
              strokeWidth={bw * 0.4}
              fill="none"
              strokeLinecap="round"
            />
            {/* small thorn/bud at tip */}
            <circle
              cx={tx}
              cy={ty}
              r={bw * 0.5 + 0.5}
              fill="#5a9a52"
              opacity={0.7}
            />
          </g>
        );
      })}

      {/* ── Leaves ── */}
      {plant.leaves.map((leaf) => {
        let ax: number, ay: number;
        if (leaf.branchId != null) {
          const branch = plant.branches.find((b) => b.id === leaf.branchId);
          if (!branch) return null;
          const tip = branchTip(branch);
          ax = tip.tx;
          ay = tip.ty;
        } else {
          const pt = stemPt(leaf.heightFraction);
          ax = pt.x;
          ay = pt.y;
        }

        const swayA = Math.sin(tick / 20 + leaf.swayOffset) * 6;
        const dir = leaf.side === "left" ? -1 : 1;
        const rot = dir * 35 + swayA;
        const lx = leaf.length * leaf.scale;
        const ly = leaf.length * 0.4 * leaf.scale;
        const hue = 110 + leaf.id * 3;
        const lit = 30 + leaf.id * 1.8;
        const c1 = `hsl(${hue},65%,${lit}%)`;
        const c2 = `hsl(${hue},55%,${lit + 14}%)`;

        return (
          <g
            key={`lf${leaf.id}`}
            transform={`translate(${ax},${ay}) rotate(${rot})`}
            filter="url(#lsh)"
            opacity={Math.min(leaf.scale * 1.4, 1)}
          >
            {/* Leaf shape — custom path for more natural look */}
            <path
              d={`M0,0 Q${dir * lx * 0.3},${-ly * 0.9} ${dir * lx},${-ly * 0.15}
                  Q${dir * lx * 0.55},${ly * 0.5} 0,0`}
              fill={c1}
            />
            {/* Midrib */}
            <line
              x1={0}
              y1={0}
              x2={dir * lx * 0.95}
              y2={-ly * 0.12}
              stroke={c2}
              strokeWidth={0.9}
              opacity={0.7}
            />
            {/* Side veins */}
            {[0.25, 0.45, 0.65, 0.8].map((t, vi) => {
              const vx = dir * lx * t * 0.95;
              const vy = -ly * 0.12 * t;
              return (
                <line
                  key={vi}
                  x1={vx}
                  y1={vy}
                  x2={vx + dir * lx * 0.12}
                  y2={vy - ly * (0.35 + vi * 0.08)}
                  stroke={c2}
                  strokeWidth={0.55}
                  opacity={0.45}
                />
              );
            })}
          </g>
        );
      })}

      {/* ── Fruits on branches and stem ── */}
      {plant.fruits.map((fruit) => {
        const leaf = plant.leaves.find((l) => l.id === fruit.leafId);
        if (!leaf) return null;

        let ox: number, oy: number;
        if (fruit.branchId != null) {
          const branch = plant.branches.find((b) => b.id === fruit.branchId);
          if (!branch) return null;
          const tip = branchTip(branch);
          ox = tip.tx;
          oy = tip.ty;
        } else {
          const pt = stemPt(leaf.heightFraction);
          ox = pt.x;
          oy = pt.y;
        }

        const fSway = Math.sin(tick / 25 + fruit.swayOffset) * 3;
        const dir = fruit.side === "left" ? -1 : 1;
        const fr = fruit.size * fruit.scale;
        const fx = ox + dir * (12 + fr) + fSway;
        const fy = oy + 4 * fruit.scale;

        return (
          <g
            key={`fr${fruit.id}`}
            filter="url(#fglow)"
            opacity={Math.min(fruit.scale * 1.3, 1)}
          >
            {/* Hanging stem */}
            <path
              d={`M${ox + dir * 3} ${oy} Q${(ox + fx) / 2} ${oy - 4} ${fx} ${fy - fr}`}
              stroke="#4a7c42"
              strokeWidth={1}
              fill="none"
              strokeLinecap="round"
            />
            {/* Fruit body */}
            <circle cx={fx} cy={fy} r={fr} fill={fruit.color} />
            {/* Depth gradient */}
            <circle
              cx={fx + fr * 0.15}
              cy={fy + fr * 0.15}
              r={fr * 0.7}
              fill="rgba(0,0,0,0.12)"
            />
            {/* Shine */}
            <circle
              cx={fx - fr * 0.25}
              cy={fy - fr * 0.3}
              r={fr * 0.3}
              fill="white"
              opacity={0.4}
            />
            {/* Calyx (small leaves on top) */}
            <ellipse
              cx={fx - 2}
              cy={fy - fr - 1}
              rx={fr * 0.35}
              ry={fr * 0.15}
              fill="#3d7a30"
              opacity={0.85}
              transform={`rotate(-15,${fx - 2},${fy - fr - 1})`}
            />
            <ellipse
              cx={fx + 2}
              cy={fy - fr - 1}
              rx={fr * 0.35}
              ry={fr * 0.15}
              fill="#4a8a3a"
              opacity={0.75}
              transform={`rotate(15,${fx + 2},${fy - fr - 1})`}
            />
          </g>
        );
      })}

      {/* ── Top bud → flower ── */}
      {progress > 0.55 &&
        (() => {
          const bs = Math.min((progress - 0.55) / 0.3, 1);
          const tx = s2x;
          const ty = s2y - 4;
          const ps = Math.sin(tick / 32) * 5;

          return (
            <g opacity={bs}>
              {/* Sepals (green base petals) */}
              {[0, 72, 144, 216, 288].map((deg) => {
                const r = ((deg + ps * 0.5) * Math.PI) / 180;
                return (
                  <ellipse
                    key={`sep${deg}`}
                    cx={tx + Math.cos(r) * 7 * bs}
                    cy={ty + Math.sin(r) * 7 * bs}
                    rx={4.5 * bs}
                    ry={2 * bs}
                    fill="#4a8c42"
                    opacity={0.6}
                    transform={`rotate(${deg},${tx + Math.cos(r) * 7 * bs},${ty + Math.sin(r) * 7 * bs})`}
                  />
                );
              })}
              {/* Petals — larger, appear after 80% */}
              {progress > 0.8 &&
                [0, 45, 90, 135, 180, 225, 270, 315].map((deg) => {
                  const petalScale = Math.min((progress - 0.8) / 0.15, 1);
                  const r = ((deg + ps) * Math.PI) / 180;
                  const pd = 10 * petalScale * bs;
                  return (
                    <ellipse
                      key={`pet${deg}`}
                      cx={tx + Math.cos(r) * pd}
                      cy={ty + Math.sin(r) * pd}
                      rx={5 * petalScale * bs}
                      ry={2.8 * petalScale * bs}
                      fill={deg % 90 === 0 ? "#fde68a" : "#fcd34d"}
                      opacity={0.9}
                      transform={`rotate(${deg + ps},${tx + Math.cos(r) * pd},${ty + Math.sin(r) * pd})`}
                    />
                  );
                })}
              {/* Centre */}
              <circle cx={tx} cy={ty} r={5.5 * bs} fill="#f9c74f" />
              <circle cx={tx} cy={ty} r={3 * bs} fill="#f3722c" />
              {/* Orbiting pollen */}
              {progress > 0.88 &&
                [0, 1, 2, 3, 4, 5].map((i) => {
                  const a = (tick / 18 + i * 1.05) % (Math.PI * 2);
                  const or = 13 * bs;
                  return (
                    <circle
                      key={`pln${i}`}
                      cx={tx + Math.cos(a) * or}
                      cy={ty + Math.sin(a) * or}
                      r={1.3}
                      fill="#fde68a"
                      opacity={0.65}
                    />
                  );
                })}
            </g>
          );
        })()}
    </svg>
  );
}

// ─── Growth Chart ─────────────────────────────────────────────────────────────

const GrowthChart = memo(function GrowthChart({
  heightHistory,
  leafHistory,
  yieldHistory,
  yieldRateHistory,
}: {
  heightHistory: number[];
  leafHistory: number[];
  yieldHistory: number[];
  yieldRateHistory: number[];
}) {
  const t = useTranslations("plantSimulator");

  const chartOptions = {
    responsive: true,
    maintainAspectRatio: false,
    animation: { duration: 0 },
    plugins: {
      legend: { labels: { font: { size: 11 } } },
      title: {
        display: true,
        text: t("chartTitle"),
        font: { size: 14 },
      },
    },
    scales: {
      x: {
        ticks: { maxTicksLimit: 8 },
      },
      yHeight: {
        type: "linear" as const,
        position: "left" as const,
        min: 0,
        max: MAX_HEIGHT,
        title: { display: true, text: t("chartHeight") },
      },
      yLeaf: {
        type: "linear" as const,
        position: "right" as const,
        min: 0,
        max: MAX_LEAVES,
        grid: { display: false },
        title: { display: true, text: t("chartLeaves") },
      },
      yYield: {
        type: "linear" as const,
        position: "left" as const,
        min: 0,
        max: MAX_YIELD,
        display: false,
        grid: { display: false },
      },
      yYieldRate: {
        type: "linear" as const,
        position: "right" as const,
        min: 0,
        display: false,
        grid: { display: false },
      },
    },
  };

  const labels = heightHistory.map((_, i) => `${i}s`);

  const data = {
    labels,
    datasets: [
      {
        label: t("chartHeightPx"),
        data: heightHistory,
        borderColor: "#4a7c59",
        backgroundColor: "rgba(74,124,89,0.10)",
        fill: true,
        tension: 0.4,
        pointRadius: 0,
        yAxisID: "yHeight",
      },
      {
        label: t("chartLeafCount"),
        data: leafHistory,
        borderColor: "#f9c74f",
        backgroundColor: "rgba(249,199,79,0.10)",
        fill: true,
        tension: 0.4,
        pointRadius: 0,
        yAxisID: "yLeaf",
      },
      {
        label: t("chartYield"),
        data: yieldHistory,
        borderColor: "#f97316",
        backgroundColor: "rgba(249,115,22,0.10)",
        fill: true,
        tension: 0.4,
        pointRadius: 0,
        yAxisID: "yYield",
      },
      {
        label: t("chartYieldRate"),
        data: yieldRateHistory,
        borderColor: "#a78bfa",
        backgroundColor: "rgba(167,139,250,0.10)",
        fill: true,
        tension: 0.4,
        pointRadius: 0,
        borderDash: [4, 3],
        yAxisID: "yYieldRate",
      },
    ],
  };

  return (
    <Box
      className="is-full"
      sx={{
        minHeight: { xs: 380, sm: 340, md: 320 },
        height: { xs: 380, sm: 340, md: 320 },
      }}
    >
      <Line data={data} options={chartOptions} />
    </Box>
  );
});

// ─── Main Component ───────────────────────────────────────────────────────────

const INIT_PLANT: PlantState = {
  height: 0,
  leaves: [],
  branches: [],
  fruits: [],
  tick: 0,
  yield: 0,
  yieldRate: 0,
};

export default function PlantSimulator() {
  const [running, setRunning] = useState(false);
  const [speed, setSpeed] = useState(1.5);
  const [env, setEnv] = useState<EnvironmentSettings>({ light: 75, water: 65 });

  const [plant, setPlant] = useState<PlantState>(INIT_PLANT);
  const [heightHistory, setHeightHistory] = useState<number[]>([0]);
  const [leafHistory, setLeafHistory] = useState<number[]>([0]);
  const [yieldHistory, setYieldHistory] = useState<number[]>([0]);
  const [yieldRateHistory, setYieldRateHistory] = useState<number[]>([0]);

  const intervalRef = useRef<ReturnType<typeof setInterval> | null>(null);
  const tickRef = useRef(0);
  const historyIntervalRef = useRef<ReturnType<typeof setInterval> | null>(
    null,
  );
  const plantRef = useRef<PlantState>(plant);
  plantRef.current = plant;

  const reset = useCallback(() => {
    setPlant(INIT_PLANT);
    setHeightHistory([0]);
    setLeafHistory([0]);
    setYieldHistory([0]);
    setYieldRateHistory([0]);
    tickRef.current = 0;
  }, []);

  // Stop simulation when plant reaches max height
  useEffect(() => {
    if (plant.height >= MAX_HEIGHT && running) setRunning(false);
  }, [plant.height, running]);

  // Main simulation tick at ~20fps (reduced from 30fps to prevent browser overload)
  useEffect(() => {
    if (!running) {
      if (intervalRef.current) clearInterval(intervalRef.current);
      return;
    }

    intervalRef.current = setInterval(() => {
      tickRef.current += 1;
      const t = tickRef.current;

      setPlant((prev) => {
        const rate = growthRate(env, speed);
        const newHeight = Math.min(prev.height + rate * 0.4, MAX_HEIGHT);
        const hp = newHeight / MAX_HEIGHT;

        // ── Branches: appear after 30% growth ──
        const newBranches = [...prev.branches];
        const expectedBranches = Math.min(
          Math.floor((hp - 0.3) / 0.12),
          MAX_BRANCHES,
        );
        while (newBranches.length < Math.max(0, expectedBranches)) {
          const bid = newBranches.length;
          newBranches.push({
            id: bid,
            side: bid % 2 === 0 ? "left" : "right",
            heightFraction: 0.25 + bid * 0.11,
            length: 30 + Math.random() * 25,
            angle: -(25 + Math.random() * 20),
            scale: 0,
            swayOffset: Math.random() * Math.PI * 2,
            thickness: 2.5 + Math.random() * 1.5,
          });
        }
        const grownBranches = newBranches.map((b) => ({
          ...b,
          scale: Math.min(b.scale + 0.012, 1),
        }));

        // ── Leaves: on main stem + on branch tips ──
        const newLeaves = [...prev.leaves];
        const expectedStemLeaves = Math.min(
          Math.floor(newHeight / LEAF_INTERVAL_PX),
          MAX_LEAVES,
        );

        // Stem leaves (fixed: use 'added' counter; nextId-newLeaves.length was always 0 → infinite loop)
        const stemLeafCount = newLeaves.filter(
          (l) => l.branchId === null,
        ).length;
        let nextId = newLeaves.length;
        let added = 0;
        while (stemLeafCount + added < expectedStemLeaves) {
          const idx = stemLeafCount + added;
          newLeaves.push({
            id: nextId,
            side: idx % 2 === 0 ? "left" : "right",
            heightFraction: (idx + 1) / (expectedStemLeaves + 1),
            scale: 0,
            swayOffset: Math.random() * Math.PI * 2,
            length: 16 + Math.random() * 14,
            branchId: null,
          });
          nextId++;
          added++;
        }

        // Branch-tip leaves (1 per mature branch, once branch scale > 0.6)
        for (const b of grownBranches) {
          if (b.scale > 0.6) {
            const hasLeaf = newLeaves.some((l) => l.branchId === b.id);
            if (!hasLeaf) {
              newLeaves.push({
                id: nextId++,
                side: b.side,
                heightFraction: b.heightFraction,
                scale: 0,
                swayOffset: Math.random() * Math.PI * 2,
                length: 14 + Math.random() * 10,
                branchId: b.id,
              });
            }
          }
        }

        const grownLeaves = newLeaves.map((l) => ({
          ...l,
          scale: Math.min(l.scale + 0.018, 1),
        }));

        // ── Yield ──
        const currentYieldRate = computeYieldRate(env, grownLeaves.length, hp);
        const newYield = Math.min(
          prev.yield + currentYieldRate * 0.033,
          MAX_YIELD,
        );

        // ── Fruits: appear after 45% on branches, then some on stem ──
        const newFruits = [...prev.fruits];
        const maxFruits = Math.min(
          Math.floor((hp - 0.45) / 0.08),
          grownBranches.length + 3,
        );
        let fNextId = newFruits.length;
        while (newFruits.length < Math.max(0, maxFruits)) {
          const fid = fNextId++;
          // First fruits on branches, then on stem leaves
          const onBranch = fid < grownBranches.length;
          const targetBranch = onBranch ? grownBranches[fid] : null;
          const targetLeaf = onBranch
            ? grownLeaves.find((l) => l.branchId === targetBranch!.id) ||
              grownLeaves[fid]
            : grownLeaves[Math.min(fid, grownLeaves.length - 1)];
          if (!targetLeaf) break;
          newFruits.push({
            id: fid,
            branchId: onBranch ? targetBranch!.id : null,
            leafId: targetLeaf.id,
            side: targetLeaf.side === "left" ? "right" : "left",
            scale: 0,
            swayOffset: Math.random() * Math.PI * 2,
            color: FRUIT_COLORS[fid % FRUIT_COLORS.length],
            size: 5 + Math.random() * 4,
          });
        }

        const grownFruits = newFruits.map((f) => ({
          ...f,
          scale: Math.min(f.scale + 0.014, 1),
        }));

        return {
          height: newHeight,
          leaves: grownLeaves,
          branches: grownBranches,
          fruits: grownFruits,
          tick: t,
          yield: newYield,
          yieldRate: currentYieldRate,
        };
      });
    }, 50);

    return () => {
      if (intervalRef.current) clearInterval(intervalRef.current);
    };
  }, [running, speed, env]);

  // History logging every 1 second (reads from plantRef to avoid setPlant side-effects)
  useEffect(() => {
    if (!running) {
      if (historyIntervalRef.current) clearInterval(historyIntervalRef.current);
      return;
    }

    historyIntervalRef.current = setInterval(() => {
      const p = plantRef.current;
      setHeightHistory((h) => [...h.slice(-59), Math.round(p.height)]);
      setLeafHistory((l) => [...l.slice(-59), p.leaves.length]);
      setYieldHistory((y) => [...y.slice(-59), parseFloat(p.yield.toFixed(1))]);
      setYieldRateHistory((r) => [...r.slice(-59), p.yieldRate]);
    }, 1000);

    return () => {
      if (historyIntervalRef.current) clearInterval(historyIntervalRef.current);
    };
  }, [running]);

  const t = useTranslations("plantSimulator");
  const isFinished = plant.height >= MAX_HEIGHT;

  const statItems: {
    value: string | number;
    label: string;
    color: "success" | "warning" | "error" | "secondary";
  }[] = [
    { value: Math.round(plant.height), label: t("height"), color: "success" },
    { value: plant.leaves.length, label: t("leaves"), color: "warning" },
    { value: plant.branches.length, label: t("branches"), color: "success" },
    { value: plant.fruits.length, label: t("fruits"), color: "error" },
    { value: plant.yield.toFixed(1), label: t("yield"), color: "warning" },
    {
      value: plant.yieldRate.toFixed(2),
      label: t("yieldRate"),
      color: "secondary",
    },
  ];

  const primaryPanelSx = {
    height: "100%",
    minHeight: { xs: "auto", lg: 780 },
  };

  return (
    <Box className="flex flex-col gap-6 min-is-0 is-full">
      <Grid container spacing={6} className="min-is-0 is-full">
        {/* ── Plant visualization ── */}
        <Grid size={{ xs: 12, lg: 6 }} className="flex">
          <Card
            className="is-full flex flex-col items-center p-6"
            sx={primaryPanelSx}
          >
            <CardContent
              className="flex flex-col items-center gap-4 is-full p-0"
              sx={{ flex: 1 }}
            >
              <PlantSVG plant={plant} tick={plant.tick} running={running} />

              <Grid container spacing={2} className="is-full">
                {statItems.map((item, idx) => (
                  <Grid key={idx} size={{ xs: 4 }}>
                    <Card variant="outlined" className="text-center p-2.5">
                      <Typography variant="h6" color={item.color}>
                        {item.value}
                      </Typography>
                      <Typography variant="caption" color="text.secondary">
                        {item.label}
                      </Typography>
                    </Card>
                  </Grid>
                ))}
              </Grid>

              {isFinished && (
                <Typography
                  variant="body2"
                  color="warning.main"
                  className="font-medium animate-pulse"
                >
                  🌼 {t("maxGrowthReached")}
                </Typography>
              )}
            </CardContent>
          </Card>
        </Grid>

        {/* ── Chart ── */}
        <Grid size={{ xs: 12, lg: 6 }} className="flex">
          <Card className="p-6 flex flex-col" sx={primaryPanelSx}>
            <CardContent sx={{ flex: 1 }}>
              <GrowthChart
                heightHistory={heightHistory}
                leafHistory={leafHistory}
                yieldHistory={yieldHistory}
                yieldRateHistory={yieldRateHistory}
              />

              <Grid container spacing={4} className="mt-6">
                <Grid size={{ xs: 12, sm: 6, lg: 3 }}>
                  <Card variant="outlined" className="p-4">
                    <Typography
                      variant="body2"
                      color="text.secondary"
                      className="mbe-1"
                    >
                      {t("progressGrowth")}
                    </Typography>
                    <Box
                      className="w-full rounded-full overflow-hidden bg-action-hover mbe-1"
                      sx={{ height: 8 }}
                    >
                      <Box
                        className="bg-success rounded-full h-full transition-all"
                        sx={{ width: `${(plant.height / MAX_HEIGHT) * 100}%` }}
                      />
                    </Box>
                    <Typography
                      variant="body2"
                      color="success.main"
                      fontWeight="bold"
                    >
                      {Math.round((plant.height / MAX_HEIGHT) * 100)}%
                    </Typography>
                  </Card>
                </Grid>
                <Grid size={{ xs: 12, sm: 6, lg: 3 }}>
                  <Card variant="outlined" className="p-4">
                    <Typography
                      variant="body2"
                      color="text.secondary"
                      className="mbe-1"
                    >
                      {t("lightStatus")}
                    </Typography>
                    <Box
                      className="w-full rounded-full overflow-hidden bg-action-hover mbe-1"
                      sx={{ height: 8 }}
                    >
                      <Box
                        className="bg-warning rounded-full h-full transition-all"
                        sx={{ width: `${env.light}%` }}
                      />
                    </Box>
                    <Typography
                      variant="body2"
                      color="warning.main"
                      fontWeight="bold"
                    >
                      {env.light}%
                    </Typography>
                  </Card>
                </Grid>
                <Grid size={{ xs: 12, sm: 6, lg: 3 }}>
                  <Card variant="outlined" className="p-4">
                    <Typography
                      variant="body2"
                      color="text.secondary"
                      className="mbe-1"
                    >
                      {t("waterStatus")}
                    </Typography>
                    <Box
                      className="w-full rounded-full overflow-hidden bg-action-hover mbe-1"
                      sx={{ height: 8 }}
                    >
                      <Box
                        className="bg-info rounded-full h-full transition-all"
                        sx={{ width: `${env.water}%` }}
                      />
                    </Box>
                    <Typography
                      variant="body2"
                      color="info.main"
                      fontWeight="bold"
                    >
                      {env.water}%
                    </Typography>
                  </Card>
                </Grid>
                <Grid size={{ xs: 12, sm: 6, lg: 3 }}>
                  <Card variant="outlined" className="p-4">
                    <Typography
                      variant="body2"
                      color="text.secondary"
                      className="mbe-1"
                    >
                      {t("yieldStatus")}
                    </Typography>
                    <Box
                      className="w-full rounded-full overflow-hidden bg-action-hover mbe-1"
                      sx={{ height: 8 }}
                    >
                      <Box
                        className="bg-warning rounded-full h-full transition-all"
                        sx={{ width: `${(plant.yield / MAX_YIELD) * 100}%` }}
                      />
                    </Box>
                    <Box className="flex justify-between items-center">
                      <Typography
                        variant="body2"
                        color="warning.main"
                        fontWeight="bold"
                      >
                        {plant.yield.toFixed(1)}g
                      </Typography>
                      <Typography variant="caption" color="secondary.main">
                        {plant.yieldRate.toFixed(3)} g/s
                      </Typography>
                    </Box>
                  </Card>
                </Grid>
              </Grid>

              <Card variant="outlined" className="mt-6 p-4">
                <Typography
                  variant="body2"
                  color="text.secondary"
                  className="leading-6"
                >
                  {t("description")}
                </Typography>
              </Card>
            </CardContent>
          </Card>
        </Grid>
      </Grid>

      <Grid container spacing={6} className="min-is-0 is-full">
        {/* ── Controls ── */}
        <Grid size={12} className="flex">
          <Card className="is-full p-5" sx={{ width: "100%" }}>
            <CardContent className="space-y-4 p-0">
              <Typography
                variant="subtitle1"
                component="h2"
                className="font-semibold"
              >
                {t("controls")}
              </Typography>

              <Box className="flex gap-2">
                <Button
                  variant="contained"
                  color={running ? "error" : "success"}
                  onClick={() => setRunning((r) => !r)}
                  disabled={isFinished}
                  fullWidth
                >
                  {running ? `⏸ ${t("stop")}` : `▶ ${t("start")}`}
                </Button>
                <Button
                  variant="outlined"
                  color="secondary"
                  onClick={() => {
                    setRunning(false);
                    reset();
                  }}
                >
                  ↺ {t("reset")}
                </Button>
              </Box>

              <Box>
                <Typography
                  variant="body2"
                  color="text.secondary"
                  className="flex justify-between mbe-1"
                >
                  <span>{t("growthSpeed")}</span>
                  <span className="font-medium">{speed.toFixed(1)}×</span>
                </Typography>
                <input
                  type="range"
                  min={0.5}
                  max={5}
                  step={0.5}
                  value={speed}
                  onChange={(e) => setSpeed(Number(e.target.value))}
                  className="w-full"
                />
              </Box>

              <Box>
                <Typography
                  variant="body2"
                  color="text.secondary"
                  className="flex justify-between mbe-1"
                >
                  <span>☀️ {t("light")}</span>
                  <span className="font-medium">{env.light}%</span>
                </Typography>
                <input
                  type="range"
                  min={0}
                  max={100}
                  step={5}
                  value={env.light}
                  onChange={(e) =>
                    setEnv((prev) => ({
                      ...prev,
                      light: Number(e.target.value),
                    }))
                  }
                  className="w-full"
                />
              </Box>

              <Box>
                <Typography
                  variant="body2"
                  color="text.secondary"
                  className="flex justify-between mbe-1"
                >
                  <span>💧 {t("water")}</span>
                  <span className="font-medium">{env.water}%</span>
                </Typography>
                <input
                  type="range"
                  min={0}
                  max={100}
                  step={5}
                  value={env.water}
                  onChange={(e) =>
                    setEnv((prev) => ({
                      ...prev,
                      water: Number(e.target.value),
                    }))
                  }
                  className="w-full"
                />
              </Box>

              <Card variant="outlined" className="p-3">
                <Typography variant="caption" color="text.secondary">
                  {t("effectiveRate")}{" "}
                  <Typography
                    component="span"
                    variant="caption"
                    color="success.main"
                    fontWeight="bold"
                  >
                    {growthRate(env, speed).toFixed(2)}×
                  </Typography>
                </Typography>
              </Card>
            </CardContent>
          </Card>
        </Grid>
      </Grid>
    </Box>
  );
}
