/* TerraBloom Interactive ecosystem prototype */
const { useMemo, useState } = React;
const {
  checkRequirements,
  placeOrToggleOrganism,
  calculateHealth,
  calculateStatus,
} = window.EcosystemLogic;
const {
  ORGANISMS,
  PLACEMENT_SLOTS,
  PROGRESSION_ORDER,
  OBJECTIVES,
} = window.EcosystemConfig;

const TYPE_ORDER = ["Abiotic", "Producer", "Primary consumer", "Secondary consumer"];
const SUN_RAY_ANGLES = [0, 45, 90, 135, 180, 225, 270, 315];

function formatNaturalList(items) {
  if (items.length <= 1) {
    return items[0] || "";
  }
  if (items.length === 2) {
    return `${items[0]} and ${items[1]}`;
  }
  return `${items.slice(0, -1).join(", ")}, and ${items[items.length - 1]}`;
}

function OrgIcon({ id, className }) {
  switch (id) {
    case "sun":
      return (
        <svg viewBox="0 0 64 64" className={className} aria-hidden="true">
          <circle cx="32" cy="32" r="14" fill="#F5C04A" stroke="#3A2A1F" strokeWidth="3" />
          {SUN_RAY_ANGLES.map((angle) => {
            const r = (angle * Math.PI) / 180;
            return (
              <line
                key={angle}
                x1={32 + Math.cos(r) * 20}
                y1={32 + Math.sin(r) * 20}
                x2={32 + Math.cos(r) * 28}
                y2={32 + Math.sin(r) * 28}
                stroke="#3A2A1F"
                strokeWidth="3"
                strokeLinecap="round"
              />
            );
          })}
        </svg>
      );
    case "water":
      return (
        <svg viewBox="0 0 64 64" className={className} aria-hidden="true">
          <path
            d="M32 8 C24 22 16 30 16 40 a16 16 0 0 0 32 0 C48 30 40 22 32 8 Z"
            fill="#7DC4E0"
            stroke="#3A2A1F"
            strokeWidth="3"
            strokeLinejoin="round"
          />
        </svg>
      );
    case "grass":
      return (
        <svg viewBox="0 0 64 64" className={className} aria-hidden="true">
          <path
            d="M16 50 L16 30 M24 50 L24 22 M32 50 L32 18 M40 50 L40 22 M48 50 L48 30"
            stroke="#7AB648"
            strokeWidth="5"
            strokeLinecap="round"
          />
          <path d="M10 50 L54 50" stroke="#3A2A1F" strokeWidth="3" strokeLinecap="round" />
        </svg>
      );
    case "tree":
      return (
        <svg viewBox="0 0 64 64" className={className} aria-hidden="true">
          <rect x="28" y="36" width="8" height="20" fill="#7B5230" stroke="#3A2A1F" strokeWidth="3" />
          <path
            d="M32 8 L52 36 L42 36 L56 50 L8 50 L22 36 L12 36 Z"
            fill="#4F8A35"
            stroke="#3A2A1F"
            strokeWidth="3"
            strokeLinejoin="round"
          />
        </svg>
      );
    case "bee":
      return (
        <svg viewBox="0 0 64 64" className={className} aria-hidden="true">
          <ellipse cx="32" cy="34" rx="14" ry="10" fill="#F5C04A" stroke="#3A2A1F" strokeWidth="3" />
          <path d="M28 24 L28 44 M34 24 L34 44" stroke="#3A2A1F" strokeWidth="3" />
          <ellipse cx="22" cy="26" rx="7" ry="4" fill="#fff" stroke="#3A2A1F" strokeWidth="2" />
          <ellipse cx="42" cy="26" rx="7" ry="4" fill="#fff" stroke="#3A2A1F" strokeWidth="2" />
        </svg>
      );
    case "rabbit":
      return (
        <svg viewBox="0 0 64 64" className={className} aria-hidden="true">
          <ellipse cx="32" cy="40" rx="14" ry="10" fill="#E8D5B7" stroke="#3A2A1F" strokeWidth="3" />
          <circle cx="32" cy="28" r="8" fill="#E8D5B7" stroke="#3A2A1F" strokeWidth="3" />
          <ellipse cx="28" cy="18" rx="3" ry="8" fill="#E8D5B7" stroke="#3A2A1F" strokeWidth="3" />
          <ellipse cx="36" cy="18" rx="3" ry="8" fill="#E8D5B7" stroke="#3A2A1F" strokeWidth="3" />
        </svg>
      );
    case "bird":
      return (
        <svg viewBox="0 0 64 64" className={className} aria-hidden="true">
          <path
            d="M14 36 Q26 20 40 26 L52 22 L46 32 L52 36 Q40 50 26 46 Z"
            fill="#3E8FB0"
            stroke="#3A2A1F"
            strokeWidth="3"
            strokeLinejoin="round"
          />
          <circle cx="44" cy="28" r="1.5" fill="#3A2A1F" />
        </svg>
      );
    case "fox":
      return (
        <svg viewBox="0 0 64 64" className={className} aria-hidden="true">
          <path
            d="M16 44 L24 24 L30 32 L34 32 L40 24 L48 44 Z"
            fill="#E07A3E"
            stroke="#3A2A1F"
            strokeWidth="3"
            strokeLinejoin="round"
          />
          <circle cx="26" cy="36" r="1.5" fill="#3A2A1F" />
          <circle cx="38" cy="36" r="1.5" fill="#3A2A1F" />
        </svg>
      );
    default:
      return null;
  }
}

function App() {
  const [placed, setPlaced] = useState(new Set());
  const [warning, setWarning] = useState(null);
  const [pulseId, setPulseId] = useState(null);
  const [eventFeedback, setEventFeedback] = useState("Start with Sunlight and Rain to wake up Earth.");
  const [whyMatters, setWhyMatters] = useState(
    "Ecosystems need both non-living factors and living organisms to stay healthy.",
  );

  const organismById = useMemo(
    () => ORGANISMS.reduce((acc, item) => ({ ...acc, [item.id]: item }), {}),
    [],
  );

  const unlocksById = useMemo(() => {
    const map = {};
    for (const organism of ORGANISMS) {
      map[organism.id] = [];
    }
    for (const organism of ORGANISMS) {
      for (const req of organism.requires) {
        map[req].push(organism.name);
      }
    }
    return map;
  }, []);

  const health = useMemo(() => calculateHealth(placed.size, ORGANISMS.length), [placed]);
  const status = useMemo(() => calculateStatus(placed.size), [placed]);

  const progressionIndex = useMemo(() => {
    let count = 0;
    for (const id of PROGRESSION_ORDER) {
      if (!placed.has(id)) {
        break;
      }
      count += 1;
    }
    return count;
  }, [placed]);

  const objective = useMemo(() => {
    if (placed.size === ORGANISMS.length) {
      return OBJECTIVES.complete;
    }
    const nextId = PROGRESSION_ORDER.find((id) => !placed.has(id));
    if (!nextId) {
      return OBJECTIVES.complete;
    }
    const nextOrganism = organismById[nextId];
    const missing = nextOrganism.requires.filter((req) => !placed.has(req));
    if (missing.length === 0) {
      return `Objective: add ${nextOrganism.name} next.`;
    }
    const missingNames = formatNaturalList(missing.map((id) => organismById[id].name));
    return `Objective: unlock ${nextOrganism.name} by placing ${missingNames}.`;
  }, [placed, organismById]);

  const groupedOrganisms = useMemo(() => {
    return TYPE_ORDER.map((type) => ({
      type,
      items: ORGANISMS.filter((item) => item.type === type),
    })).filter((group) => group.items.length > 0);
  }, []);

  function place(id) {
    const wasPlaced = placed.has(id);
    const result = placeOrToggleOrganism(id, placed, ORGANISMS);
    setPlaced(result.nextPlaced);
    setWarning(result.warning);
    setPulseId(result.pulseId);

    if (result.warning) {
      setEventFeedback(result.warning);
      setWhyMatters("Order matters in ecosystems. Some organisms cannot survive without prerequisites.");
    } else if (wasPlaced) {
      setEventFeedback(`${organismById[id].name} removed. Dependent species may decline.`);
      setWhyMatters("When one species disappears, connected species can also collapse.");
    } else {
      setEventFeedback(`Great choice! ${organismById[id].chainReaction}`);
      setWhyMatters(organismById[id].why);
    }

    if (result.pulseTimeoutMs !== null) {
      setTimeout(() => setPulseId(null), result.pulseTimeoutMs);
    }
    if (result.warningTimeoutMs !== null) {
      setTimeout(() => setWarning(null), result.warningTimeoutMs);
    }
  }

  function reset() {
    setPlaced(new Set());
    setWarning(null);
    setPulseId(null);
    setEventFeedback("Planet reset. Start again with Sunlight and Rain.");
    setWhyMatters("Strong ecosystems grow step by step from basic needs.");
  }

  const greenness = placed.size / ORGANISMS.length;
  const earthBg = `radial-gradient(circle at 30% 28%,
    ${greenness > 0.1 ? "#E5F0CF" : "#F0DBA8"} 0%,
    ${greenness > 0.2 ? "#A9D879" : "#E2B476"} 22%,
    ${greenness > 0.4 ? "#7AB648" : "#C99963"} 45%,
    ${greenness > 0.6 ? "#4F8A35" : "#A26538"} 75%,
    ${greenness > 0.8 ? "#2C5A22" : "#7B4F2A"} 100%)`;

  const waterReady = placed.has("water");
  const plantsReady = placed.has("grass") && placed.has("tree");
  const balanceReady = placed.has("bird") && placed.has("fox");

  return (
    <div className="tb-shell" aria-label="TerraBloom ecosystem prototype">
      <section className="tb-hud" aria-label="Game status">
        <div className="tb-health-card">
          <div className="tb-health-header">
            <span>Ecosystem health</span>
            <span style={{ color: status.color }}>{status.label}</span>
          </div>
          <div className="tb-meter-track" aria-hidden="true">
            <div className="tb-meter-fill" style={{ width: `${health}%` }} />
          </div>
          <div className="tb-health-footer">
            <span>
              <b>{placed.size}</b> / {ORGANISMS.length} linked
            </span>
            <button type="button" className="tb-reset" onClick={reset} aria-label="Reset ecosystem">
              Reset planet ↻
            </button>
          </div>
        </div>
        <div className="tb-progress" aria-label="Unlock progression">
          {PROGRESSION_ORDER.map((id, index) => {
            const item = organismById[id];
            const isPlaced = placed.has(id);
            const isCurrent = index === progressionIndex && !isPlaced;
            return (
              <div key={id} className="tb-step-wrap">
                <div className={`tb-step ${isPlaced ? "is-done" : ""} ${isCurrent ? "is-current" : ""}`}>
                  {index + 1}
                </div>
                <span>{item.name}</span>
              </div>
            );
          })}
        </div>
      </section>

      <section className="tb-main-grid">
        <article className="tb-planet-panel" aria-label="Planet stage">
          <h2>Grassland world</h2>
          <p>Watch Earth shift from barren to blooming as species connect.</p>

          <div className="tb-earth" style={{ background: earthBg }}>
            {[...placed].map((id) => {
              const slot = PLACEMENT_SLOTS.find((item) => item.id === id);
              if (!slot) {
                return null;
              }
              return (
                <div
                  key={id}
                  className="tb-placed"
                  style={{
                    left: `${slot.x}%`,
                    top: `${slot.y}%`,
                    width: `${slot.size}%`,
                    animation: "tb-pop .5s cubic-bezier(.34,1.56,.64,1)",
                  }}
                >
                  <OrgIcon id={id} className="tb-icon" />
                </div>
              );
            })}

            {placed.size === 0 && (
              <svg viewBox="0 0 200 200" className="tb-cracks" aria-hidden="true">
                <path
                  d="M40 80 L70 90 L80 110 L100 100 M120 60 L140 90 L130 120 L160 130 M60 140 L90 150 L100 170"
                  stroke="#7B4F2A"
                  strokeWidth="2"
                  fill="none"
                  opacity="0.6"
                  strokeLinecap="round"
                />
              </svg>
            )}

            <div className="tb-overlays">
              <span className={`tb-overlay ${waterReady ? "on" : ""}`}>💧 Water cycle</span>
              <span className={`tb-overlay ${plantsReady ? "on" : ""}`}>🌿 Plant cover</span>
              <span className={`tb-overlay ${balanceReady ? "on" : ""}`}>🦊 Predator balance</span>
            </div>
          </div>

          {warning && (
            <div className="tb-warning" role="status" aria-live="polite">
              ⚠ {warning}
            </div>
          )}
        </article>

        <aside className="tb-cards-panel" aria-label="Organism cards">
          <h2>Add organisms</h2>
          <p>Place cards in order to keep your ecosystem alive.</p>

          {groupedOrganisms.map((group) => (
            <div key={group.type} className="tb-group">
              <h3>{group.type}</h3>
              <div className="tb-cards-grid">
                {group.items.map((item) => {
                  const isPlaced = placed.has(item.id);
                  const allowed = checkRequirements(item.id, placed, ORGANISMS);
                  const requirements = item.requires.length
                    ? item.requires.map((id) => organismById[id].name).join(" + ")
                    : "None";
                  const unlocks = unlocksById[item.id].length ? unlocksById[item.id].join(", ") : "None";
                  return (
                    <button
                      key={item.id}
                      type="button"
                      className={`tb-card ${isPlaced ? "placed" : ""} ${!isPlaced && !allowed ? "locked" : ""} ${pulseId === item.id + "-shake" ? "shake" : ""}`}
                      onClick={() => place(item.id)}
                      aria-label={`${item.name} card. ${isPlaced ? "Placed" : "Not placed"}. Needs ${requirements}. Unlocks ${unlocks}.`}
                    >
                      <span className="tb-card-icon">
                        <OrgIcon id={item.id} className="tb-icon" />
                      </span>
                      <span className="tb-card-main">
                        <span className="tb-card-title">{item.name}</span>
                        <span className="tb-card-desc">{item.desc}</span>
                        <span className="tb-card-meta">Needs: {requirements}</span>
                        <span className="tb-card-meta">Unlocks: {unlocks}</span>
                      </span>
                      <span className="tb-check" aria-hidden="true">
                        {isPlaced ? "✓" : "+"}
                      </span>
                    </button>
                  );
                })}
              </div>
            </div>
          ))}
        </aside>
      </section>

      <section className="tb-learning" aria-label="Learning panel">
        <div className="tb-learning-card">
          <h3>Current objective</h3>
          <p>{objective || OBJECTIVES.start}</p>
        </div>
        <div className="tb-learning-card">
          <h3>Chain reaction</h3>
          <p>{eventFeedback}</p>
        </div>
        <div className="tb-learning-card">
          <h3>Why this matters</h3>
          <p>{whyMatters}</p>
        </div>
      </section>

      <div className="tb-live" role="status" aria-live="polite" aria-atomic="true">
        {eventFeedback}
      </div>

      <style>{`
        .tb-shell {
          display: grid;
          gap: 18px;
          color: #1b1b17;
        }
        .tb-hud {
          display: grid;
          grid-template-columns: 1.1fr .9fr;
          gap: 14px;
        }
        .tb-health-card, .tb-progress, .tb-planet-panel, .tb-cards-panel, .tb-learning-card {
          background: #fff;
          border: 2px solid #3A2A1F;
          border-radius: 20px;
          box-shadow: 0 8px 0 #3A2A1F;
        }
        .tb-health-card {
          padding: 14px;
        }
        .tb-health-header {
          display: flex;
          justify-content: space-between;
          font-family: "Bricolage Grotesque";
          font-weight: 800;
          font-size: 13px;
          text-transform: uppercase;
          letter-spacing: .04em;
          margin-bottom: 8px;
        }
        .tb-meter-track {
          height: 14px;
          border: 2px solid #3A2A1F;
          border-radius: 999px;
          background: #f5edd8;
          overflow: hidden;
        }
        .tb-meter-fill {
          height: 100%;
          background: linear-gradient(90deg, #E07A3E, #F5C04A 50%, #7AB648 100%);
          transition: width .4s ease;
        }
        .tb-health-footer {
          display: flex;
          justify-content: space-between;
          align-items: center;
          margin-top: 10px;
          font-size: 14px;
        }
        .tb-reset {
          border: 2px solid #3A2A1F;
          border-radius: 999px;
          padding: 6px 12px;
          background: #f5edd8;
          font-family: "Bricolage Grotesque";
          font-weight: 700;
          cursor: pointer;
        }
        .tb-progress {
          padding: 12px;
          display: grid;
          grid-template-columns: repeat(8, minmax(0, 1fr));
          gap: 6px;
          align-items: start;
        }
        .tb-step-wrap {
          display: grid;
          justify-items: center;
          gap: 4px;
          text-align: center;
          font-size: 10px;
          font-weight: 700;
          color: #3a4a3f;
        }
        .tb-step {
          width: 24px;
          height: 24px;
          border-radius: 50%;
          border: 2px solid #3A2A1F;
          background: #fff;
          display: grid;
          place-items: center;
          font-weight: 800;
        }
        .tb-step.is-done { background: #7AB648; color: #fff; }
        .tb-step.is-current { background: #F5C04A; }

        .tb-main-grid {
          display: grid;
          grid-template-columns: 1fr 1fr;
          gap: 18px;
        }
        .tb-planet-panel,
        .tb-cards-panel {
          padding: 18px;
        }
        .tb-planet-panel h2,
        .tb-cards-panel h2 {
          font-family: "Bricolage Grotesque";
          color: #214332;
          margin-bottom: 4px;
        }
        .tb-planet-panel p,
        .tb-cards-panel p {
          font-size: 14px;
          color: #3a4a3f;
          margin-bottom: 12px;
        }

        .tb-earth {
          position: relative;
          width: 100%;
          aspect-ratio: 1/1;
          border-radius: 50%;
          border: 3px solid #3A2A1F;
          overflow: hidden;
          box-shadow: inset -22px -28px 60px rgba(0,0,0,.35), inset 18px 22px 40px rgba(255,255,255,.18);
          transition: background .6s ease;
        }
        .tb-placed {
          position: absolute;
          transform: translate(-50%, -50%);
          filter: drop-shadow(0 2px 0 rgba(0,0,0,.25));
        }
        .tb-icon { width: 100%; height: auto; }
        .tb-cracks {
          position: absolute;
          inset: 0;
          width: 100%;
          height: 100%;
        }
        .tb-overlays {
          position: absolute;
          left: 10px;
          right: 10px;
          bottom: 12px;
          display: flex;
          flex-wrap: wrap;
          gap: 6px;
          justify-content: center;
        }
        .tb-overlay {
          border-radius: 999px;
          border: 2px solid #3A2A1F;
          background: rgba(255,255,255,.82);
          padding: 4px 10px;
          font-size: 11px;
          font-weight: 700;
          opacity: .45;
        }
        .tb-overlay.on { opacity: 1; background: #F5EDD8; }
        .tb-warning {
          margin-top: 10px;
          background: #E07A3E;
          color: #fff;
          border: 2px solid #3A2A1F;
          border-radius: 999px;
          padding: 8px 12px;
          font-size: 13px;
          font-weight: 700;
          text-align: center;
        }

        .tb-group + .tb-group { margin-top: 12px; }
        .tb-group h3 {
          font-family: "Bricolage Grotesque";
          font-size: 14px;
          color: #214332;
          text-transform: uppercase;
          letter-spacing: .08em;
          margin-bottom: 8px;
        }
        .tb-cards-grid {
          display: grid;
          gap: 8px;
        }
        .tb-card {
          width: 100%;
          display: grid;
          grid-template-columns: 42px 1fr 22px;
          align-items: start;
          gap: 10px;
          border: 2px solid #3A2A1F;
          border-radius: 14px;
          background: #fff;
          padding: 10px;
          text-align: left;
          cursor: pointer;
          font-family: inherit;
          transition: transform .12s, box-shadow .12s, opacity .12s;
          box-shadow: 0 4px 0 #3A2A1F;
        }
        .tb-card:hover { transform: translateY(-1px); }
        .tb-card:focus-visible,
        .tb-reset:focus-visible {
          outline: 3px solid #7DC4E0;
          outline-offset: 2px;
        }
        .tb-card.placed { background: #e7f2d2; }
        .tb-card.locked { opacity: .75; }
        .tb-card-icon {
          width: 42px;
          height: 42px;
          border: 2px solid #3A2A1F;
          border-radius: 10px;
          padding: 5px;
          display: grid;
          place-items: center;
          background: #f5edd8;
        }
        .tb-card-main { display: grid; gap: 3px; min-width: 0; }
        .tb-card-title {
          font-family: "Bricolage Grotesque";
          color: #214332;
          font-weight: 800;
          font-size: 15px;
          line-height: 1.15;
        }
        .tb-card-desc {
          color: #3a4a3f;
          font-size: 12px;
          line-height: 1.25;
        }
        .tb-card-meta {
          color: #7b6a4f;
          font-size: 11px;
          line-height: 1.25;
          font-weight: 700;
        }
        .tb-check {
          width: 22px;
          height: 22px;
          border: 2px solid #3A2A1F;
          border-radius: 50%;
          display: grid;
          place-items: center;
          font-weight: 800;
          font-size: 12px;
        }

        .tb-learning {
          display: grid;
          grid-template-columns: repeat(3, 1fr);
          gap: 12px;
        }
        .tb-learning-card {
          padding: 14px;
        }
        .tb-learning-card h3 {
          font-family: "Bricolage Grotesque";
          font-size: 15px;
          color: #214332;
          margin-bottom: 6px;
        }
        .tb-learning-card p {
          font-size: 13px;
          color: #3a4a3f;
          line-height: 1.4;
        }

        .tb-live {
          position: absolute;
          width: 1px;
          height: 1px;
          margin: -1px;
          padding: 0;
          border: 0;
          overflow: hidden;
          clip: rect(0 0 0 0);
          white-space: nowrap;
        }

        @keyframes tb-pop {
          0% { transform: translate(-50%, -50%) scale(0); }
          70% { transform: translate(-50%, -50%) scale(1.2); }
          100% { transform: translate(-50%, -50%) scale(1); }
        }
        @keyframes tb-shake {
          0%, 100% { transform: translateX(0); }
          25% { transform: translateX(-5px); }
          75% { transform: translateX(5px); }
        }
        .tb-card.shake { animation: tb-shake .4s; }

        @media (max-width: 1100px) {
          .tb-hud,
          .tb-main-grid,
          .tb-learning {
            grid-template-columns: 1fr;
          }
          .tb-progress {
            grid-template-columns: repeat(4, minmax(0, 1fr));
          }
        }
      `}</style>
    </div>
  );
}

const rootNode = document.getElementById("eco-app");
if (rootNode) {
  const root = ReactDOM.createRoot(rootNode);
  root.render(<App />);
}
