// ============================================================
// App root - Authentification Discord OAuth2 & Router RBAC
// ============================================================

const { useState: aUseState, useEffect: aUseEffect, useMemo: aUseMemo } = React;

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = { hasError: false, error: null };
  }
  static getDerivedStateFromError(error) {
    return { hasError: true, error };
  }
  componentDidCatch(error, errorInfo) {
    console.error("WebPanel Error Caught:", error, errorInfo);
  }
  render() {
    if (this.state.hasError) {
      return (
        <div className="card" style={{ padding: 40, textAlign: "center", maxWidth: 600, margin: "30px auto" }}>
          <Icon name="warn" size={36} style={{ color: "var(--danger)", marginBottom: 12 }} />
          <h2>Une erreur inattendue est survenue</h2>
          <p style={{ color: "var(--text-dim)", fontSize: 13, lineHeight: 1.5, margin: "10px 0 20px" }}>
            {this.state.error?.message || "Une erreur est survenue lors de l'affichage de ce module."}
          </p>
          <button
            className="btn btn-primary"
            onClick={() => {
              this.setState({ hasError: false, error: null });
              window.location.reload();
            }}
          >
            Recharger la page
          </button>
        </div>
      );
    }
    return this.props.children;
  }
}

function LoginScreen({ onLoginSuccess, devMode, devRoles, authError, serverName, serverLogo }) {
  const [loading, setLoading] = aUseState(false);
  const [devLoading, setDevLoading] = aUseState(null);

  const handleDiscordClick = () => {
    setLoading(true);
    // Si la page a été ouverte sur le port 8080 (live-server statique), rediriger vers le vrai backend port 3000
    if (window.location.port === "8080" || window.location.port === "5500") {
      window.location.href = "http://localhost:3000/auth/discord";
      return;
    }
    // Redirection vers le flux OAuth2 sécurisé du serveur
    window.location.href = "/auth/discord";
  };

  const handleDevLogin = async (roleKey) => {
    setDevLoading(roleKey);
    try {
      const resp = await fetch("/auth/dev-login", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ roleKey }),
      });
      const data = await resp.json();
      if (resp.ok) {
        onLoginSuccess();
      } else {
        alert("Erreur: " + (data.error || "Échec de connexion"));
      }
    } catch (err) {
      alert("Erreur de connexion au serveur");
    } finally {
      setDevLoading(null);
    }
  };

  return (
    <div className="login-wrap">
      <div className="login-card" style={{ width: "100%", maxWidth: 460 }}>
        {serverLogo ? (
          <img src={serverLogo} alt="" style={{ width: 56, height: 56, borderRadius: 14, objectFit: "cover", marginBottom: 20 }} />
        ) : (
          <div className="lg-logo">{(serverName || "N")[0].toUpperCase()}</div>
        )}
        <h2>Console - {serverName || "Gestion serveur"}</h2>
        <p>Connectez-vous avec votre compte Discord pour accéder aux outils d'administration de {serverName || "votre serveur"}.</p>

        {authError && (
          <div style={{
            marginBottom: 20,
            padding: "10px 14px",
            background: "oklch(0.35 0.15 25 / 0.2)",
            border: "1px solid oklch(0.5 0.15 25 / 0.4)",
            borderRadius: 8,
            fontSize: 12,
            color: "var(--danger)",
            display: "flex",
            alignItems: "center",
            gap: 8,
          }}>
            <Icon name="warn" size={16} />
            <span>{decodeURIComponent(authError)}</span>
          </div>
        )}

        <button className="btn-discord" onClick={handleDiscordClick} disabled={loading}>
          {loading ? (
            <>
              <span style={{ display: "inline-block", width: 14, height: 14, border: "2px solid rgba(255,255,255,0.3)", borderTopColor: "white", borderRadius: "50%", animation: "spin 0.7s linear infinite" }}></span>
              Redirection vers Discord…
            </>
          ) : (
            <>
              <Icon name="discord" size={18} />
              Se connecter avec Discord
            </>
          )}
        </button>

        {devMode && (
          <div style={{ marginTop: 24, paddingTop: 18, borderTop: "1px solid var(--border)" }}>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 10 }}>
              <span style={{ fontSize: 11, fontWeight: 600, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--warn)" }}>
                ⚙ Testeur de grades (Mode DEV)
              </span>
              <span className="dev-pill" style={{ fontSize: 9 }}>Dev active</span>
            </div>
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8 }}>
              {devRoles && Object.entries(devRoles).map(([k, r]) => (
                <button
                  key={k}
                  className="btn btn-sm"
                  style={{ textAlign: "left", fontSize: 11, padding: "8px 10px", lineHeight: 1.3 }}
                  disabled={devLoading !== null}
                  onClick={() => handleDevLogin(k)}
                >
                  <strong style={{ display: "block", color: "var(--text)" }}>{r.name.split(" (")[0]}</strong>
                  <span style={{ color: "var(--muted)", fontSize: 10 }}>({r.name.split(" (")[1] || ""}</span>
                </button>
              ))}
            </div>
          </div>
        )}
      </div>

      <style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>
    </div>
  );
}

function App() {
  const [authState, setAuthState] = aUseState({
    loading: true,
    user: null,
    permissions: null,
    serverName: "Mon Serveur RP",
    serverLogo: "",
    devMode: false,
    devRoles: null,
  });
  const [page, setPage] = aUseState("logs");
  const [authError, setAuthError] = aUseState(null);
  const [mobileOpen, setMobileOpen] = aUseState(false);

  // Auto-redirection si ouvert sur port 8080 (live-server statique) vers port 3000 (backend Node.js)
  aUseEffect(() => {
    if (window.location.port === "8080" || window.location.port === "5500") {
      window.location.href = "http://localhost:3000" + window.location.search;
    }
  }, []);

  // Récupérer la configuration du serveur (nom et logo)
  aUseEffect(() => {
    fetch("/api/config")
      .then((r) => r.json())
      .then((cfg) => {
        if (cfg.serverName) {
          setAuthState((s) => ({ ...s, serverName: cfg.serverName, serverLogo: cfg.serverLogo || "" }));
        }
      })
      .catch(() => {});
  }, []);

  // Check auth error in query string
  aUseEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const err = params.get("auth_error");
    if (err) {
      setAuthError(err);
      window.history.replaceState({}, document.title, window.location.pathname);
    }
  }, []);

  // Fetch current session from server API
  const checkSession = async () => {
    try {
      const resp = await fetch("/api/me");
      if (resp.ok) {
        const data = await resp.json();
        setAuthState((s) => ({
          ...s,
          loading: false,
          user: data.user,
          permissions: data.permissions,
          serverName: data.serverName || s.serverName,
          serverLogo: data.serverLogo !== undefined ? data.serverLogo : s.serverLogo,
          devMode: data.devMode,
          devRoles: data.devRoles,
        }));
      } else {
        // Not authenticated
        setAuthState((s) => ({ ...s, loading: false, user: null, permissions: null }));
      }
    } catch (e) {
      setAuthState((s) => ({ ...s, loading: false, user: null, permissions: null }));
    }
  };

  aUseEffect(() => {
    checkSession();
  }, []);

  const { user, permissions, loading, devMode, devRoles, serverName, serverLogo } = authState;

  // Auto-switch to first authorized page if current page isn't allowed
  aUseEffect(() => {
    if (!permissions) return;
    const allowed = [];
    if (permissions.logsView) allowed.push("logs");
    if (permissions.shopView) allowed.push("shop");
    if (permissions.filesView) allowed.push("files");

    if (allowed.length > 0 && !allowed.includes(page)) {
      setPage(allowed[0]);
    }
  }, [permissions, page]);

  const handleLogout = async () => {
    try {
      await fetch("/auth/logout", { method: "POST" });
    } catch (e) {}
    setAuthState((s) => ({ ...s, user: null, permissions: null }));
  };

  if (loading) {
    return (
      <div className="login-wrap">
        <div style={{ textAlign: "center" }}>
          <div className="spinner" style={{ width: 28, height: 28, margin: "0 auto 14px", borderWidth: 3 }}></div>
          <div style={{ color: "var(--text-dim)", fontSize: 13 }}>Vérification de la session sécurisée…</div>
        </div>
      </div>
    );
  }

  if (!user) {
    return (
      <LoginScreen
        onLoginSuccess={checkSession}
        devMode={devMode}
        devRoles={devRoles}
        authError={authError}
        serverName={serverName}
        serverLogo={serverLogo}
      />
    );
  }

  const titles = {
    logs: { title: "Logs serveur", crumb: "Surveillance" },
    shop: { title: "Logs boutique", crumb: "Transactions" },
    files: { title: "Configuration serveur", crumb: "Fichiers & Scripts" },
  };
  const cur = titles[page] || { title: "Console", crumb: "Administration" };

  const navItems = [
    { id: "logs", label: "Logs serveur", icon: "logs", visible: permissions.logsView },
    { id: "shop", label: "Logs boutique", icon: "cart", visible: permissions.shopView },
    { id: "files", label: "Configuration", icon: "folderOpen", visible: permissions.filesView },
  ].filter((n) => n.visible);

  // Format permission badges for topbar & sidebar
  const activeTags = [];
  if (permissions?.missingRequiredRole) {
    activeTags.push("Grade obligatoire manquant");
  } else if (permissions?.isAdmin) {
    activeTags.push("Admin Total");
  } else if (permissions) {
    if (permissions.logsView) activeTags.push(permissions.logsSensitive ? "Logs (Sensibles)" : "Logs");
    if (permissions.shopView) activeTags.push(permissions.shopEuroEquiv ? "Boutique (EUR €)" : "Boutique");
    if (permissions.filesView) {
      if (permissions.filesPush) activeTags.push("Config (Push)");
      else if (permissions.filesEdit) activeTags.push("Config (Édition)");
      else activeTags.push("Config (Lecture)");
    }
  }
  const tagLabels = activeTags.join(" · ") || "Aucun accès";

  return (
    <div className={`app ${mobileOpen ? "sb-open" : ""}`}>
      {/* Overlay backdrop pour fermeture sur mobile / responsive */}
      <div
        className={`sidebar-backdrop ${mobileOpen ? "active" : ""}`}
        onClick={() => setMobileOpen(false)}
        aria-hidden="true"
      />

      <aside className={`sidebar ${mobileOpen ? "open" : ""}`}>
        <div className="sb-brand">
          {serverLogo ? (
            <img src={serverLogo} alt="" style={{ width: 32, height: 32, borderRadius: 8, objectFit: "cover" }} />
          ) : (
            <div className="logo">{(serverName || "N")[0].toUpperCase()}</div>
          )}
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="name">Console</div>
            <div className="sub">{serverName || "Serveur FiveM"}</div>
          </div>
          <button className="sb-close-btn" onClick={() => setMobileOpen(false)} title="Fermer le menu" aria-label="Fermer le menu">
            <Icon name="x" size={16} />
          </button>
        </div>

        <div className="sb-section">Pages</div>
        {navItems.map((n) => (
          <div
            key={n.id}
            className={`nav-item ${page === n.id ? "active" : ""}`}
            onClick={() => {
              setPage(n.id);
              setMobileOpen(false);
            }}
          >
            <Icon name={n.icon} className="ico" />
            <span>{n.label}</span>
          </div>
        ))}

        {navItems.length === 0 && (
          <div style={{ padding: "14px 10px", fontSize: 12, color: "var(--danger)", background: "oklch(0.35 0.15 25 / 0.15)", borderRadius: 8, margin: "10px 0" }}>
            <Icon name="discord" size={14} style={{ verticalAlign: "middle", marginRight: 6, color: "#5865F2" }} />
            {permissions?.missingRequiredRole
              ? "Grade Discord obligatoire manquant sur votre compte. Contactez un administrateur."
              : "Aucun grade autorisé sur Discord pour accéder aux sections du panel."}
          </div>
        )}

        <div className="sb-bottom">
          {user.avatar ? (
            <img src={user.avatar} alt="" className="avatar" style={{ objectFit: "cover" }} />
          ) : (
            <div className="avatar">{(user.displayName || user.username || "DA").slice(0, 2).toUpperCase()}</div>
          )}
          <div className="who">
            <div className="n">{user.displayName || user.username}</div>
            <div className="r" title={tagLabels}>{tagLabels}</div>
          </div>
          <button className="sb-logout" title="Se déconnecter" onClick={handleLogout}>
            <Icon name="logout" />
          </button>
        </div>
      </aside>

      <main className="main">
        <div className="topbar">
          <button
            className="sb-toggle-btn"
            onClick={() => setMobileOpen(!mobileOpen)}
            title="Menu de navigation"
            aria-label="Ouvrir le menu de navigation"
          >
            <Icon name="menu" size={18} />
          </button>
          <div className="topbar-title-wrap">
            <div className="crumb">{cur.crumb}</div>
            <h1>{cur.title}</h1>
          </div>
          <div className="spacer"></div>
          {devMode && <span className="dev-pill">Mode Dev</span>}
          <span className="role-pill" title={tagLabels} style={{ color: permissions?.missingRequiredRole ? "var(--danger)" : undefined }}>
            {tagLabels}
          </span>
        </div>

        <div className="content">
          <ErrorBoundary>
            {page === "logs" && permissions?.logsView && <LogsPage user={user} perms={permissions} serverName={serverName} serverLogo={serverLogo} />}
            {page === "shop" && permissions?.shopView && <ShopPage user={user} perms={permissions} serverName={serverName} serverLogo={serverLogo} />}
            {page === "files" && permissions?.filesView && <FilesPage user={user} perms={permissions} serverName={serverName} serverLogo={serverLogo} />}
            {navItems.length === 0 && (
              <div className="card" style={{ padding: 40, textAlign: "center" }}>
                <Icon name="lock" size={36} style={{ color: "var(--danger)", marginBottom: 12 }} />
                <h2>{permissions?.missingRequiredRole ? "Accès Verrouillé - Grade Obligatoire Requis" : "Accès Restreint"}</h2>
                <p style={{ color: "var(--text-dim)", maxWidth: 500, margin: "10px auto", lineHeight: 1.6 }}>
                  {permissions?.missingRequiredRole ? (
                    <>
                      Votre compte Discord (<strong>{user.username}</strong>) ne possède pas le <strong>grade d'accès obligatoire</strong> configuré pour ce panel. Même avec d'autres rôles (ex: Admin ou Staff), ce rôle spécifique est indispensable pour débloquer les données.
                    </>
                  ) : (
                    <>
                      Votre compte Discord (<strong>{user.username}</strong>) n'a actuellement aucun rôle lui donnant accès à cette console de gestion. Contactez un administrateur pour recevoir les rôles requis sur le Discord.
                    </>
                  )}
                </p>
              </div>
            )}
          </ErrorBoundary>
        </div>
      </main>
    </div>
  );
}

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