/* ============ SCREEN PHASES + WINDOW MANAGER + TASKBAR ============ */
/* global React, ReactDOM, PrzelomAudio */

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

// ====================================================================
// SVG PIXEL-ART ICONS
// ====================================================================
const ICON = {
  about: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="3"
        y="3"
        width="18"
        height="18"
        rx="2"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.1)"
      />
      <circle cx="12" cy="9" r="2.5" fill="currentColor" />
      <path
        d="M6 18c1-3 3.5-4 6-4s5 1 6 4"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
      />
    </svg>
  ),
  services: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <path
        d="M12 2 L20 7 L20 17 L12 22 L4 17 L4 7 Z"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.15)"
      />
      <path
        d="M12 7 L16 9.5 L16 14.5 L12 17 L8 14.5 L8 9.5 Z"
        fill="currentColor"
        opacity="0.85"
      />
    </svg>
  ),
  portfolio: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="3"
        y="6"
        width="18"
        height="14"
        rx="1.5"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.1)"
      />
      <path
        d="M9 6 V4 a1 1 0 0 1 1-1 h4 a1 1 0 0 1 1 1 V6"
        stroke="currentColor"
        strokeWidth="1.5"
      />
      <rect x="6" y="10" width="4" height="3" fill="currentColor" />
      <rect
        x="11"
        y="10"
        width="7"
        height="1.5"
        fill="currentColor"
        opacity="0.6"
      />
      <rect
        x="11"
        y="13"
        width="5"
        height="1.5"
        fill="currentColor"
        opacity="0.6"
      />
      <rect
        x="6"
        y="16"
        width="12"
        height="1.5"
        fill="currentColor"
        opacity="0.6"
      />
    </svg>
  ),
  process: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <circle cx="6" cy="6" r="2.5" fill="currentColor" />
      <circle cx="18" cy="6" r="2.5" stroke="currentColor" strokeWidth="1.5" />
      <circle cx="18" cy="18" r="2.5" fill="currentColor" />
      <circle cx="6" cy="18" r="2.5" stroke="currentColor" strokeWidth="1.5" />
      <path
        d="M8.5 6 H15.5 M18 8.5 V15.5 M15.5 18 H8.5 M6 15.5 V8.5"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeDasharray="2 2"
      />
    </svg>
  ),
  team: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <circle
        cx="8"
        cy="8"
        r="3"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.2)"
      />
      <circle cx="16" cy="9" r="2.5" stroke="currentColor" strokeWidth="1.5" />
      <path
        d="M3 19c1-3 2.5-4.5 5-4.5s4 1.5 5 4.5"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
        fill="rgba(var(--accent-rgb)/0.1)"
      />
      <path
        d="M14 18c1-2 2-3 4-3s3 1 4 3"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
      />
    </svg>
  ),
  contact: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="3"
        y="5"
        width="18"
        height="14"
        rx="1.5"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.12)"
      />
      <path
        d="M3 7 L12 13 L21 7"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinejoin="round"
      />
      <circle cx="19" cy="6" r="3" fill="var(--red)" />
    </svg>
  ),
  terminal: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="2"
        y="4"
        width="20"
        height="16"
        rx="1.5"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(0,0,0,0.5)"
      />
      <path
        d="M5 9 L8 11.5 L5 14"
        stroke="currentColor"
        strokeWidth="1.6"
        strokeLinecap="round"
        strokeLinejoin="round"
      />
      <rect x="10" y="14" width="6" height="1.5" fill="currentColor" />
    </svg>
  ),
  doom: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <path
        d="M4 5 L20 5 L18 19 L6 19 Z"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(255,51,68,0.25)"
      />
      <circle cx="9" cy="11" r="1.5" fill="currentColor" />
      <circle cx="15" cy="11" r="1.5" fill="currentColor" />
      <path
        d="M8 15 Q12 13 16 15"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
      />
    </svg>
  ),
  readme: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <path
        d="M5 3 H17 L19 5 V21 H5 Z"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.1)"
      />
      <path d="M14 3 V6 H17" stroke="currentColor" strokeWidth="1.5" />
      <rect x="8" y="9" width="8" height="1.2" fill="currentColor" />
      <rect x="8" y="12" width="8" height="1.2" fill="currentColor" />
      <rect x="8" y="15" width="5" height="1.2" fill="currentColor" />
    </svg>
  ),
  music: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <circle
        cx="12"
        cy="12"
        r="9"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.15)"
      />
      <circle cx="12" cy="12" r="3" stroke="currentColor" strokeWidth="1.5" />
      <circle cx="12" cy="12" r="1" fill="currentColor" />
      <path d="M12 6 L12 9" stroke="currentColor" strokeWidth="1.5" />
    </svg>
  ),
  settings: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <path
        d="M12 2 L13.5 4 L16 3.5 L17 6 L19 7 L18.5 9.5 L20 11 L18.5 14 L19 17 L17 18 L16 20.5 L13.5 20 L12 22 L10.5 20 L8 20.5 L7 18 L5 17 L5.5 14 L4 11 L5.5 9.5 L5 7 L7 6 L8 3.5 L10.5 4 Z"
        stroke="currentColor"
        strokeWidth="1.2"
        fill="rgba(var(--accent-rgb)/0.15)"
      />
      <circle
        cx="12"
        cy="12"
        r="3"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="currentColor"
      />
    </svg>
  ),
  files: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <path
        d="M3 7 a1 1 0 0 1 1-1 h6 l2 2 h8 a1 1 0 0 1 1 1 v10 a1 1 0 0 1 -1 1 H4 a1 1 0 0 1 -1 -1 z"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.18)"
      />
      <rect
        x="3"
        y="10"
        width="18"
        height="9"
        rx="1"
        fill="currentColor"
        opacity="0.2"
      />
    </svg>
  ),
  browser: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="2"
        y="3"
        width="20"
        height="18"
        rx="1.5"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.1)"
      />
      <path d="M2 8 L22 8" stroke="currentColor" strokeWidth="1.5" />
      <circle cx="5" cy="5.5" r="0.8" fill="currentColor" />
      <circle cx="7.5" cy="5.5" r="0.8" fill="currentColor" />
      <circle cx="10" cy="5.5" r="0.8" fill="currentColor" />
      <circle
        cx="12"
        cy="14.5"
        r="3.5"
        stroke="currentColor"
        strokeWidth="1.3"
      />
      <path
        d="M12 11 V14.5 L14 16"
        stroke="currentColor"
        strokeWidth="1.3"
        strokeLinecap="round"
      />
    </svg>
  ),
  ai: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <circle
        cx="12"
        cy="12"
        r="9"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.15)"
      />
      <path
        d="M8 10 L8 16 M8 13 L11 13 M11 10 L11 16"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
      />
      <path
        d="M14 10 L14 16 M14 10 L17 10 M14 13 L16.5 13 M14 16 L17 16"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
      />
    </svg>
  ),
  stats: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="3"
        y="3"
        width="18"
        height="18"
        rx="1.5"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.08)"
      />
      <rect x="6" y="14" width="2.5" height="4" fill="currentColor" />
      <rect x="10.5" y="10" width="2.5" height="8" fill="currentColor" />
      <rect x="15" y="6" width="2.5" height="12" fill="currentColor" />
    </svg>
  ),
  calendar: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="3"
        y="5"
        width="18"
        height="16"
        rx="1.5"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.1)"
      />
      <path d="M3 9 L21 9" stroke="currentColor" strokeWidth="1.5" />
      <rect x="7" y="3" width="2" height="4" rx="1" fill="currentColor" />
      <rect x="15" y="3" width="2" height="4" rx="1" fill="currentColor" />
      <rect
        x="6"
        y="12"
        width="3"
        height="3"
        fill="currentColor"
        opacity="0.6"
      />
      <rect x="11" y="12" width="3" height="3" fill="currentColor" />
      <rect
        x="16"
        y="12"
        width="3"
        height="3"
        fill="currentColor"
        opacity="0.6"
      />
    </svg>
  ),
  youtube: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="2"
        y="5"
        width="20"
        height="14"
        rx="3"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.1)"
      />
      <path d="M10 9 L16 12 L10 15 Z" fill="currentColor" />
    </svg>
  ),
  ytplayer: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <rect
        x="3"
        y="4"
        width="18"
        height="12"
        rx="1.5"
        stroke="currentColor"
        strokeWidth="1.5"
        fill="rgba(var(--accent-rgb)/0.1)"
      />
      <path
        d="M8 20 L16 20"
        stroke="currentColor"
        strokeWidth="1.5"
        strokeLinecap="round"
      />
      <path d="M12 16 L12 20" stroke="currentColor" strokeWidth="1.5" />
      <path d="M10 8 L15 10 L10 12 Z" fill="currentColor" />
    </svg>
  ),
  power: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <path
        d="M8 6 a7 7 0 1 0 8 0"
        stroke="currentColor"
        strokeWidth="1.8"
        strokeLinecap="round"
      />
      <path
        d="M12 3 V11"
        stroke="currentColor"
        strokeWidth="1.8"
        strokeLinecap="round"
      />
    </svg>
  ),
  search: (props) => (
    <svg viewBox="0 0 24 24" fill="none" {...props}>
      <circle
        cx="10.5"
        cy="10.5"
        r="6"
        stroke="currentColor"
        strokeWidth="1.6"
      />
      <path
        d="M15 15 L20 20"
        stroke="currentColor"
        strokeWidth="1.8"
        strokeLinecap="round"
      />
    </svg>
  ),
};
window.ICON = ICON;

// ====================================================================
// SCREEN: OFF (DVD bouncing "POWER OFF")
// ====================================================================
function ScreenOff() {
  const ref = useRef(null);
  useEffect(() => {
    const el = ref.current;
    if (!el) return;
    let x = 30,
      y = 30,
      vx = 0.7,
      vy = 0.5;
    let raf;
    const tick = () => {
      const parent = el.parentElement;
      if (!parent) return;
      const w = parent.offsetWidth;
      const h = parent.offsetHeight;
      const ew = el.offsetWidth;
      const eh = el.offsetHeight;
      x += vx;
      y += vy;
      if (x <= 0) {
        x = 0;
        vx = -vx;
      }
      if (y <= 0) {
        y = 0;
        vy = -vy;
      }
      if (x + ew >= w) {
        x = w - ew;
        vx = -vx;
      }
      if (y + eh >= h) {
        y = h - eh;
        vy = -vy;
      }
      el.style.left = x + "px";
      el.style.top = y + "px";
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => cancelAnimationFrame(raf);
  }, []);
  return (
    <div className="scr-off">
      <div className="scr-off-text" ref={ref}>
        POWER OFF
      </div>
    </div>
  );
}

// ====================================================================
// SCREEN: STANDBY (PRESS START button)
// ====================================================================
function ScreenStandby({ onStartClient }) {
  const ERR_PL = {
    invalid_email: "Email ma nieprawidłowy format.",
    weak_password: "Hasło musi mieć min. 8 znaków.",
    passwords_dont_match: "Hasła nie pasują do siebie.",
    email_taken: "Ten email jest już zarejestrowany. Zaloguj się.",
    invalid_credentials: "Nieprawidłowy email lub hasło.",
    user_not_found: "Nie znaleziono konta dla tego emaila.",
    wrong_password: "Hasło jest nieprawidłowe.",
    email_not_confirmed: "Email nie został potwierdzony. Sprawdź skrzynkę.",
    rate_limit: "Za dużo prób. Spróbuj za kilka minut.",
    email_send_failed: "Wysyłka maila nie powiodła się.",
    storage_unavailable: "Chwilowy problem z bazą.",
    missing_password: "Wpisz hasło.",
    invalid_session: "Sesja wygasła.",
    already_confirmed: "Email już potwierdzony.",
  };
  const errPl = (c) => ERR_PL[c] || "Błąd: " + (c || "?");

  const initialUser = window.AUTH?.user || null;
  const [view, setView] = useState(initialUser ? "welcome" : "login"); // welcome | login | register | sent
  const [email, setEmail] = useState(initialUser?.email || "");
  const [pwd, setPwd] = useState("");
  const [pwd2, setPwd2] = useState("");
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState("");
  const [info, setInfo] = useState("");
  const [devLink, setDevLink] = useState("");
  const inputRef = useRef(null);

  useEffect(() => {
    const t = setTimeout(() => inputRef.current?.focus(), 200);
    return () => clearTimeout(t);
  }, [view]);

  // Po klikniciu w link potwierdzający — pokaż info
  useEffect(() => {
    if (!window.PrzelomBus) return;
    const off = window.PrzelomBus.on("auth-confirm-result", (d) => {
      if (d.code === "confirmed") {
        setView("login");
        if (d.email) setEmail(d.email);
        setInfo("Email potwierdzony. Możesz się zalogować.");
        setErr("");
      } else if (d.code === "confirm_expired") {
        setErr("Link potwierdzający wygasł. Zarejestruj się ponownie.");
      } else if (d.code) {
        setErr("Potwierdzenie nie powiodło się: " + d.code);
      }
    });
    return () => off?.();
  }, []);

  const onLogin = async (e) => {
    e?.preventDefault?.();
    if (busy) return;
    setBusy(true);
    setErr("");
    setInfo("");
    PrzelomAudio.sounds.click();
    try {
      const { res, data } = await window.AUTH.login(email, pwd);
      if (res.ok) {
        // Boot z konfiguracją usera
        setTimeout(() => onStartClient(), 200);
      } else {
        setErr(errPl(data.error));
      }
    } catch (e) {
      setErr("Błąd sieci: " + e.message);
    } finally {
      setBusy(false);
    }
  };

  const onRegister = async (e) => {
    e?.preventDefault?.();
    if (busy) return;
    setErr("");
    setInfo("");
    if (pwd !== pwd2) {
      setErr("Hasła muszą być identyczne.");
      return;
    }
    if (pwd.length < 8) {
      setErr("Hasło musi mieć min. 8 znaków.");
      return;
    }
    setBusy(true);
    PrzelomAudio.sounds.click();
    try {
      const { res, data } = await window.AUTH.register(email, pwd, pwd2);
      if (res.ok) {
        setView("sent");
        if (data.devLink) setDevLink(data.devLink);
      } else {
        setErr(errPl(data.error));
      }
    } catch (e) {
      setErr("Błąd sieci: " + e.message);
    } finally {
      setBusy(false);
    }
  };

  const onResend = async () => {
    if (busy) return;
    setBusy(true);
    setErr("");
    try {
      const { res, data } = await window.AUTH.resendConfirmation(email);
      if (res.ok) {
        setInfo("Wysłano ponownie.");
        if (data.devLink) setDevLink(data.devLink);
      } else {
        setErr(errPl(data.error));
      }
    } catch (e) {
      setErr("Błąd sieci: " + e.message);
    } finally {
      setBusy(false);
    }
  };

  const onLogout = async () => {
    await window.AUTH.logout();
    setEmail("");
    setPwd("");
    setView("login");
    setInfo("Wylogowano.");
  };

  const onGuest = () => {
    PrzelomAudio.sounds.click();
    onStartClient();
  };

  return (
    <div className="scr-login">
      <div className="scr-login-avatar">
        <div className="scr-login-avatar-ring" />
        <div className="scr-login-avatar-mark">Z</div>
      </div>
      <div className="scr-login-brand">ZAZA/OS</div>

      {view === "welcome" && (
        <>
          <div className="scr-login-welcome">
            Witaj, <b>{email || "user"}</b>
          </div>
          <button
            type="button"
            className="scr-login-go-big"
            onClick={() => onStartClient()}
          >
            ▶ WEJDŹ DO SYSTEMU
          </button>
          <button type="button" className="scr-login-link" onClick={onLogout}>
            Wyloguj się
          </button>
        </>
      )}

      {view === "login" && (
        <>
          <form className="scr-login-form-v" onSubmit={onLogin}>
            <input
              ref={inputRef}
              type="email"
              className="scr-login-input"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder="email"
              autoComplete="email"
              required
            />
            <input
              type="password"
              className="scr-login-input"
              value={pwd}
              onChange={(e) => setPwd(e.target.value)}
              placeholder="hasło"
              autoComplete="current-password"
              required
            />
            {err && <div className="scr-login-error">{err}</div>}
            {info && <div className="scr-login-info">{info}</div>}
            <button type="submit" className="scr-login-go-big" disabled={busy}>
              {busy ? "…" : "ZALOGUJ"}
            </button>
          </form>

          <button type="button" className="scr-login-guest" onClick={onGuest}>
            Kontynuuj jako gość →
          </button>
        </>
      )}
    </div>
  );
}

// ====================================================================
// BOOT SEQUENCE
// ====================================================================
const BOOT_LINES = [
  { d: 0, t: "ZAZA/BIOS v3.0.1 — © 2026 ZAZA Studio", c: "g" },
  { d: 180, t: "CPU: Anthropic Claude · Opus 4.7 @ 1M context", c: "g" },
  { d: 260, t: "Memory: 1.0M tokens detected ............... [OK]", c: "g" },
  { d: 340, t: "Vector store: 4.8M docs ..................... [OK]", c: "g" },
  { d: 420, t: "AGENT mesh: 14/14 workers online ............ [OK]", c: "g" },
  { d: 500, t: "Detecting input devices ...........", c: "d" },
  { d: 580, t: "  → Keyboard, Mouse, Brain .................. [OK]", c: "g" },
  { d: 680, t: "Loading ZAZA/OS kernel ...", c: "d" },
  { d: 820, t: "  → mod_synthwave    .................... loaded", c: "g" },
  { d: 880, t: "  → mod_raycaster    .................... loaded", c: "g" },
  { d: 940, t: "  → mod_ai_engine    .................... loaded", c: "g" },
  { d: 1000, t: "  → mod_telepathy    .............. EXPERIMENTAL", c: "a" },
  { d: 1080, t: "Mounting /usr/przyszlosc ............... [OK]", c: "g" },
  { d: 1180, t: "Starting window manager ................ [OK]", c: "g" },
  { d: 1260, t: "", c: "g" },
  { d: 1320, t: "> Wszystko nominalnie. Witaj w 2036.", c: "a" },
  { d: 1440, t: "> Inicjalizacja środowiska_", c: "a" },
];

function BootSequence({ onDone }) {
  const [shown, setShown] = useState([]);
  const [progress, setProgress] = useState(0);
  const [phase, setPhase] = useState("boot");

  useEffect(() => {
    PrzelomAudio.sounds.boot();
    BOOT_LINES.forEach((line) => {
      setTimeout(() => {
        setShown((prev) => [...prev, line]);
        if (line.t) PrzelomAudio.sounds.keypress();
      }, line.d);
    });
    setTimeout(() => setPhase("bar"), 1600);
    let p = 0;
    const tk = setInterval(() => {
      p += 5 + Math.random() * 9;
      if (p >= 100) {
        p = 100;
        clearInterval(tk);
        setTimeout(onDone, 350);
      }
      setProgress(p);
    }, 70);
    return () => clearInterval(tk);
  }, []);

  return (
    <div className="boot-screen">
      <div className="boot-content">
        <div className="boot-lines">
          {shown.map((l, i) => (
            <div key={i} className={`boot-line c-${l.c}`}>
              {l.t || " "}
            </div>
          ))}
        </div>
        {phase === "bar" && (
          <div className="boot-bar-wrap">
            <div className="boot-bar-label">ŁADOWANIE PULPITU</div>
            <div className="boot-bar">
              <div
                className="boot-bar-fill"
                style={{ width: progress + "%" }}
              ></div>
            </div>
            <div className="boot-bar-pct">{Math.floor(progress)}%</div>
          </div>
        )}
      </div>
      {phase === "bar" && (
        <div className="boot-tagline">
          "To, co inni zobaczą za dekadę — masz teraz."
        </div>
      )}
    </div>
  );
}

// ====================================================================
// WINDOW MANAGER (constrained do ekranu monitora)
// ====================================================================
function useWindowDrag(initial, screenSize, titleHeight, getWinSize) {
  const [pos, setPos] = useState(initial);
  const posRef = useRef(pos);
  useEffect(() => {
    posRef.current = pos;
  }, [pos]);
  const drag = useRef(null);
  const onMouseDown = (e) => {
    if (e.target.closest(".win-controls") || e.target.closest(".win-resize"))
      return;
    drag.current = { x: e.clientX, y: e.clientY, ox: pos.x, oy: pos.y };
    e.preventDefault();
  };
  useEffect(() => {
    const mv = (e) => {
      if (!drag.current) return;
      const newX = drag.current.ox + (e.clientX - drag.current.x);
      const newY = drag.current.oy + (e.clientY - drag.current.y);
      // Okno nie może wyjść CAŁKOWICIE poza ekran z żadnej strony — minimum 80px widoczne
      const sw = screenSize.current?.w || 800;
      const sh = screenSize.current?.h || 600;
      const ws = getWinSize?.() || { w: 480, h: 340 };
      const TASKBAR = 32;
      const MIN_VISIBLE = 80;
      const minX = -ws.w + MIN_VISIBLE; // 80px widoczne z prawej strony okna
      const maxX = sw - MIN_VISIBLE; // 80px widoczne z lewej strony okna
      const minY = 0; // titlebar nie wychodzi w górę
      const maxY = sh - TASKBAR - titleHeight; // titlebar zawsze nad taskbar
      setPos({
        x: Math.max(minX, Math.min(maxX, newX)),
        y: Math.max(minY, Math.min(maxY, newY)),
      });
    };
    const up = () => {
      drag.current = null;
    };
    window.addEventListener("mousemove", mv);
    window.addEventListener("mouseup", up);
    return () => {
      window.removeEventListener("mousemove", mv);
      window.removeEventListener("mouseup", up);
    };
  }, []);
  return [pos, setPos, onMouseDown, posRef];
}

// Multi-direction resize: dir ∈ {n,s,w,e,nw,ne,sw,se}
// setPos pozwala resizing od N/W krawędzi też przesunąć pozycję okna
function useWindowResize(initial, minW = 280, minH = 180, getPos, setPos) {
  const [size, setSize] = useState(initial);
  const r = useRef(null);
  const startResize = (dir) => (e) => {
    const pos = getPos ? getPos() : { x: 0, y: 0 };
    r.current = {
      dir,
      x: e.clientX,
      y: e.clientY,
      w: size.w,
      h: size.h,
      px: pos.x,
      py: pos.y,
    };
    e.preventDefault();
    e.stopPropagation();
  };
  useEffect(() => {
    const mv = (e) => {
      const r0 = r.current;
      if (!r0) return;
      const dx = e.clientX - r0.x;
      const dy = e.clientY - r0.y;
      let newW = r0.w,
        newH = r0.h,
        newPx = r0.px,
        newPy = r0.py;
      if (r0.dir.includes("e")) newW = Math.max(minW, r0.w + dx);
      if (r0.dir.includes("s")) newH = Math.max(minH, r0.h + dy);
      if (r0.dir.includes("w")) {
        newW = Math.max(minW, r0.w - dx);
        newPx = r0.px + (r0.w - newW);
      }
      if (r0.dir.includes("n")) {
        newH = Math.max(minH, r0.h - dy);
        newPy = r0.py + (r0.h - newH);
      }
      setSize({ w: newW, h: newH });
      if ((r0.dir.includes("w") || r0.dir.includes("n")) && setPos) {
        setPos({ x: newPx, y: newPy });
      }
    };
    const up = () => {
      r.current = null;
    };
    window.addEventListener("mousemove", mv);
    window.addEventListener("mouseup", up);
    return () => {
      window.removeEventListener("mousemove", mv);
      window.removeEventListener("mouseup", up);
    };
  }, []);
  return [size, setSize, startResize];
}

function AppWindow({
  win,
  onClose,
  onMin,
  onFocus,
  onMaximize,
  children,
  screenSize,
}) {
  const TITLE_H = 24;
  const sizeRef = useRef(win.size);
  // pos pierwszy żeby resizeHandle z dir n/w mógł go modyfikować
  const [pos, setPos, dragHandle, posRef] = useWindowDrag(
    win.pos,
    screenSize,
    TITLE_H,
    () => sizeRef.current,
  );
  const [size, setSize, startResize] = useWindowResize(
    win.size,
    win.minW || 280,
    win.minH || 180,
    () => posRef.current,
    setPos,
  );
  useEffect(() => {
    sizeRef.current = size;
  }, [size]);

  // KEY: NIE return null gdy minimized — zachowujemy mounted komponent (state, scroll, history).
  // Tylko ukrywamy CSS-em.
  const style = win.maximized
    ? {}
    : { left: pos.x, top: pos.y, width: size.w, height: size.h };

  const Icon = ICON[win.icon];
  return (
    <div
      className={`os-window ${win.maximized ? "maxed" : ""} ${win.minimized ? "win-min-hidden" : ""}`}
      style={{ ...style, zIndex: win.z }}
      onMouseDown={() => onFocus(win.id)}
    >
      <div
        className="win-titlebar"
        onMouseDown={dragHandle}
        onDoubleClick={() => !win.fixedSize && onMaximize(win.id)}
      >
        <div className="win-title">
          <span className="win-icon">{Icon ? <Icon /> : "◆"}</span>
          <span>{win.title}</span>
        </div>
        <div className="win-controls">
          <button
            className="win-btn min"
            onClick={() => onMin(win.id)}
            title="Minimalizuj"
          >
            _
          </button>
          {!win.fixedSize && (
            <button
              className="win-btn max"
              onClick={() => onMaximize(win.id)}
              title="Maksymalizuj"
            >
              ▢
            </button>
          )}
          <button
            className="win-btn close"
            onClick={() => onClose(win.id)}
            title="Zamknij"
          >
            ×
          </button>
        </div>
      </div>
      <div className="win-body">{children}</div>
      {!win.maximized && !win.fixedSize && (
        <>
          <div
            className="win-resize win-resize-n"
            onMouseDown={startResize("n")}
          />
          <div
            className="win-resize win-resize-s"
            onMouseDown={startResize("s")}
          />
          <div
            className="win-resize win-resize-w"
            onMouseDown={startResize("w")}
          />
          <div
            className="win-resize win-resize-e"
            onMouseDown={startResize("e")}
          />
          <div
            className="win-resize win-resize-nw"
            onMouseDown={startResize("nw")}
          />
          <div
            className="win-resize win-resize-ne"
            onMouseDown={startResize("ne")}
          />
          <div
            className="win-resize win-resize-sw"
            onMouseDown={startResize("sw")}
          />
          <div
            className="win-resize win-resize-se"
            onMouseDown={startResize("se")}
          />
        </>
      )}
    </div>
  );
}

// ====================================================================
// TASKBAR (jedyny element UI na desktopie)
// ====================================================================
function Taskbar({
  windows,
  onFocus,
  onClose,
  onShutdown,
  onToggleStart,
  startOpen,
  soundOn,
  onToggleSound,
  onSpotlight,
  onSettings,
}) {
  const [time, setTime] = useState("");
  useEffect(() => {
    const t = () =>
      setTime(new Date().toLocaleTimeString("pl-PL", { hour12: false }));
    t();
    const id = setInterval(t, 1000);
    return () => clearInterval(id);
  }, []);
  return (
    <div className="taskbar">
      <button
        className={`start-btn ${startOpen ? "active" : ""}`}
        onClick={onToggleStart}
      >
        <span className="start-orb"></span>
        <span>START</span>
      </button>
      <button
        className="tb-action"
        onClick={onSpotlight}
        title="Szukaj (Ctrl+K)"
      >
        <ICON.search />
      </button>
      <button className="tb-action" onClick={onSettings} title="Ustawienia">
        <ICON.settings />
      </button>
      <div className="task-windows">
        {windows.map((w) => {
          const Icon = ICON[w.icon];
          return (
            <div
              key={w.id}
              className={`task-win ${w.minimized ? "min" : ""} ${w.focused ? "focused" : ""}`}
            >
              <span className="task-icon" onClick={() => onFocus(w.id)}>
                {Icon ? <Icon /> : "◆"}
              </span>
              <span className="task-win-name" onClick={() => onFocus(w.id)}>
                {w.title}
              </span>
              <span
                className="task-win-close"
                onClick={(e) => {
                  e.stopPropagation();
                  onClose(w.id);
                }}
                title="Zamknij"
              >
                ×
              </span>
            </div>
          );
        })}
      </div>
      <div className="tray">
        <div className="tray-stat">
          <span className="dot"></span> ONLINE
        </div>
        <div className="tray-stat">CPU 12%</div>
        <button className="tray-mute" onClick={onToggleSound} title="Sound">
          {soundOn ? "🔊" : "🔇"}
        </button>
        <div className="tray-clock">{time}</div>
        <button className="tray-power" onClick={onShutdown} title="Wyłącz">
          ⏻
        </button>
      </div>
    </div>
  );
}

// ====================================================================
// START MENU
// ====================================================================
function StartMenu({ apps, onLaunch, onClose, onShutdown }) {
  const [q, setQ] = useState("");
  const filtered = useMemo(() => {
    const lq = q.trim().toLowerCase();
    if (!lq) return apps;
    return apps.filter(
      (a) =>
        a.title.toLowerCase().includes(lq) ||
        a.desc?.toLowerCase().includes(lq) ||
        a.short?.toLowerCase().includes(lq),
    );
  }, [q, apps]);

  return (
    <>
      <div className="start-overlay" onClick={onClose}></div>
      <div className="start-menu">
        <div className="start-header">
          <div className="start-user">
            <div className="start-avatar">Z</div>
            <div>
              <div className="start-name">
                {window.AUTH?.user?.email || "zaza@studio"}
              </div>
              <div className="start-role">
                {window.AUTH?.user
                  ? "Zalogowany — pełna personalizacja"
                  : "Gość — kliknij aby się zalogować"}
              </div>
            </div>
          </div>
        </div>
        <div className="start-section-label">
          APLIKACJE · {filtered.length}/{apps.length}
        </div>
        <div className="start-apps-grid">
          {filtered.length === 0 && (
            <div className="start-empty">Brak wyników dla „{q}"</div>
          )}
          {filtered.map((a) => {
            const Icon = ICON[a.icon];
            return (
              <button
                key={a.id}
                className="start-tile"
                onClick={() => {
                  onLaunch(a.id);
                  onClose();
                }}
                title={a.desc}
              >
                <span className="start-tile-icon">{Icon ? <Icon /> : "◆"}</span>
                <span className="start-tile-name">{a.title}</span>
              </button>
            );
          })}
        </div>
        <div className="start-search">
          <span className="start-search-icon">⌕</span>
          <input
            className="start-search-input"
            placeholder="Wyszukaj aplikację…"
            value={q}
            onChange={(e) => setQ(e.target.value)}
            autoFocus
          />
          {q && (
            <button
              className="start-search-clear"
              onClick={() => setQ("")}
              aria-label="Wyczyść"
            >
              ×
            </button>
          )}
        </div>
        <div className="start-footer">
          <button
            className="start-foot-btn"
            onClick={() => {
              onLaunch("settings");
              onClose();
            }}
          >
            USTAWIENIA
          </button>
          <button className="start-foot-btn power" onClick={onShutdown}>
            ⏻ WYŁĄCZ
          </button>
        </div>
      </div>
    </>
  );
}

// ====================================================================
// SPOTLIGHT
// ====================================================================
function Spotlight({ apps, onLaunch, onClose }) {
  const [q, setQ] = useState("");
  const [sel, setSel] = useState(0);
  const inputRef = useRef(null);
  useEffect(() => {
    inputRef.current?.focus();
  }, []);
  const filtered = useMemo(() => {
    const lq = q.toLowerCase().trim();
    if (!lq) return apps;
    return apps.filter(
      (a) =>
        a.title.toLowerCase().includes(lq) || a.desc.toLowerCase().includes(lq),
    );
  }, [q, apps]);
  useEffect(() => {
    setSel(0);
  }, [q]);
  const onKey = (e) => {
    if (e.key === "Escape") {
      onClose();
    } else if (e.key === "ArrowDown") {
      e.preventDefault();
      setSel((s) => Math.min(filtered.length - 1, s + 1));
    } else if (e.key === "ArrowUp") {
      e.preventDefault();
      setSel((s) => Math.max(0, s - 1));
    } else if (e.key === "Enter" && filtered[sel]) {
      onLaunch(filtered[sel].id);
      onClose();
    }
  };
  return (
    <div className="spotlight-overlay" onClick={onClose}>
      <div className="spotlight-modal" onClick={(e) => e.stopPropagation()}>
        <input
          ref={inputRef}
          className="spotlight-input"
          placeholder="Szukaj aplikacji…"
          value={q}
          onChange={(e) => setQ(e.target.value)}
          onKeyDown={onKey}
        />
        <div className="spotlight-results">
          {filtered.map((a, i) => {
            const Icon = ICON[a.icon];
            return (
              <div
                key={a.id}
                className={`spot-result ${i === sel ? "sel" : ""}`}
                onMouseEnter={() => setSel(i)}
                onClick={() => {
                  onLaunch(a.id);
                  onClose();
                }}
              >
                <div className="spot-result-icon">{Icon ? <Icon /> : "◆"}</div>
                <div>
                  <div className="spot-result-name">{a.title}</div>
                  <div className="spot-result-desc">{a.desc}</div>
                </div>
              </div>
            );
          })}
          {filtered.length === 0 && (
            <div className="spot-result">
              <div className="spot-result-name">Brak wyników dla "{q}"</div>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// ====================================================================
// EXPORTS
// ====================================================================
Object.assign(window, {
  ScreenOff,
  ScreenStandby,
  BootSequence,
  AppWindow,
  Taskbar,
  StartMenu,
  Spotlight,
  ICON,
});
