const { useEffect, useState, useRef } = React;

/* ── Static content data ─────────────────────────────────── */
const services = [
  "Live VJing",
  "Custom Motion Graphics",
  "Projection Mapping",
  "Show-Run Visuals",
  "LED Stage Design",
  "Brand Visual Identity"
];

const serviceCards = [
  {
    title: "Live Visual Jockeying",
    tag: "01",
    icon: "🎛️",
    description: "Dynamic real-time video mixing synchronized with music, DJ sets, choreography, and live performances using Resolume Arena."
  },
  {
    title: "Custom Visual Content",
    tag: "02",
    icon: "🎬",
    description: "Tailor-made visual loops, brand animations, intros, mood-driven motion graphics, and stage-ready content for event storytelling."
  },
  {
    title: "Projection Mapping & LED",
    tag: "03",
    icon: "💡",
    description: "Immersive 3D mapping and LED screen visuals that transform stages, venues, weddings, and brand launches into visual spectacles."
  },
  {
    title: "Show-Run Visual Management",
    tag: "04",
    icon: "🎯",
    description: "Cue-based visual coordination with backstage teams, lighting, sound, and the full event flow for seamless live execution."
  }
];

const projectHighlights = [
  {
    title: "Music Festivals & Club Nights",
    tag: "Live Energy",
    description: "High-impact visuals for festivals, club nights, and prominent venues across Bangalore and India.",
    bg: "linear-gradient(135deg, #1a0a0a 0%, #3d0a12 50%, #1a0a0a 100%)"
  },
  {
    title: "Corporate Brand Launches",
    tag: "Brand Moments",
    description: "Custom visual branding and animations for product launches, gala dinners, and premium corporate events.",
    bg: "linear-gradient(135deg, #0a0f1a 0%, #0a1a3d 50%, #0a0f1a 100%)"
  },
  {
    title: "Weddings & Luxury Sangeets",
    tag: "Celebration Design",
    description: "Bespoke visual storytelling that turns wedding rituals, performances, and sangeet nights into unforgettable scenes.",
    bg: "linear-gradient(135deg, #1a1000 0%, #3d2a00 50%, #1a1000 100%)"
  }
];

const approach = [
  "Creative storytelling with technical precision",
  "Adaptive and fast under live-show pressure",
  "Cohesive visual narratives matched to theme, music, and mood"
];

const tools = [
  "Resolume Arena",
  "Adobe After Effects",
  "TouchDesigner",
  "Live video mixing",
  "LED mapping",
  "3D animation",
  "Showflow management",
  "Lighting integration",
  "Sound sync",
  "Projection calibration"
];

const testimonials = [
  {
    source: "Event Planner, Bangalore",
    quote: "Transformed our event with visuals that perfectly matched the music and mood, creating an unforgettable atmosphere."
  },
  {
    source: "Corporate Brand Manager",
    quote: "Professional, creative, and incredibly reliable — a true partner in every aspect of live show production."
  },
  {
    source: "Luxury Wedding Client",
    quote: "The visuals elevated our wedding experience beyond imagination. It was pure magic and beautifully executed."
  }
];

const navItems = [
  { href: "#home", label: "Home" },
  { href: "#about", label: "About" },
  { href: "#experience", label: "Experience" },
  { href: "#skills", label: "Skills" },
  { href: "#projects", label: "Projects" },
  { href: "#services", label: "Services" },
  { href: "#contact", label: "Contact" }
];

const heroStats = [
  { value: "6+", label: "Years Experience" },
  { value: "250+", label: "Live Shows" },
  { value: "150+", label: "Projects Completed" },
  { value: "50+", label: "Happy Clients" }
];

const experienceTimeline = [
  {
    years: "2023 - Present",
    role: "Freelance Visual Jockey",
    detail: "Designing high-intensity visuals for concerts, festivals, and corporate events."
  },
  {
    years: "2020 - 2023",
    role: "Visual Designer & Motion Artist",
    detail: "Built motion content for agencies and event production teams."
  },
  {
    years: "2018 - 2020",
    role: "VJ & Content Creator",
    detail: "Delivered visuals for local events, college fests, and cultural shows."
  }
];

const skillBars = [
  { name: "Resolume Arena", percent: 95, className: "w-95" },
  { name: "TouchDesigner", percent: 85, className: "w-85" },
  { name: "Adobe After Effects", percent: 90, className: "w-90" },
  { name: "Cinema 4D", percent: 75, className: "w-75" },
  { name: "MadMapper", percent: 80, className: "w-80" },
  { name: "Video Editing", percent: 85, className: "w-85" }
];

const featureTiles = [
  {
    title: "Electronic Stage Visuals",
    subtitle: "Live Concert Visuals",
    className: "tile-1"
  },
  {
    title: "Festival Visual Experience",
    subtitle: "Music Festival",
    className: "tile-2"
  },
  {
    title: "Club Visuals",
    subtitle: "Night Club / DJ Set",
    className: "tile-3"
  },
  {
    title: "Corporate Event Visuals",
    subtitle: "Brand & Corporate",
    className: "tile-4"
  }
];

/* ── Utilities ───────────────────────────────────────────── */
function loadExternalScript(src) {
  return new Promise((resolve, reject) => {
    const existing = document.querySelector(`script[src="${src}"]`);
    if (existing) {
      if (window.grecaptcha) { resolve(); return; }
      existing.addEventListener("load", resolve, { once: true });
      existing.addEventListener("error", reject, { once: true });
      return;
    }
    const script = document.createElement("script");
    script.src = src;
    script.async = true;
    script.defer = true;
    script.onload = () => resolve();
    script.onerror = reject;
    document.head.appendChild(script);
  });
}

async function loadRecaptchaScript(siteKey) {
  const encodedSiteKey = encodeURIComponent(siteKey);
  try {
    await loadExternalScript(`https://www.google.com/recaptcha/api.js?render=${encodedSiteKey}`);
  } catch (googleError) {
    await loadExternalScript(`https://www.recaptcha.net/recaptcha/api.js?render=${encodedSiteKey}`);
  }
}

async function requestJson(url, options = {}) {
  const response = await fetch(url, {
    headers: { "Content-Type": "application/json", ...(options.headers || {}) },
    ...options
  });
  const body = await response.json().catch(() => null);
  if (!response.ok) {
    const validationMessage = body?.errors ? Object.values(body.errors).flat().find(Boolean) : null;
    throw new Error(validationMessage || body?.title || "Request failed.");
  }
  return body;
}

function formatDateTime(value) {
  if (!value) return "—";
  return new Intl.DateTimeFormat(undefined, {
    dateStyle: "medium",
    timeStyle: "short"
  }).format(new Date(value));
}

function useRouteKind() {
  return window.location.pathname.toLowerCase().startsWith("/admin") ? "admin" : "public";
}

function createVerificationState() {
  return {
    challengeId: "",
    otp: "",
    linkToken: "",
    verificationId: "",
    verified: false,
    expiresAtUtc: "",
    resendAvailableAtUtc: "",
    resendSecondsLeft: 0,
    developmentOtp: "",
    developmentLink: "",
    status: { type: "idle", text: "" }
  };
}

/* ── Scroll reveal hook ──────────────────────────────────── */
function useScrollReveal() {
  useEffect(() => {
    const els = document.querySelectorAll(".reveal");
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            entry.target.classList.add("visible");
            observer.unobserve(entry.target);
          }
        });
      },
      { threshold: 0.12 }
    );
    els.forEach(el => observer.observe(el));
    return () => observer.disconnect();
  }, []);
}

/* ── App Root ─────────────────────────────────────────────── */
function App() {
  const routeKind = useRouteKind();
  useEffect(() => {
    document.body.classList.toggle("admin-route", routeKind === "admin");
    return () => document.body.classList.remove("admin-route");
  }, [routeKind]);
  return routeKind === "admin" ? <AdminApp /> : <PublicApp />;
}

/* ════════════════════════════════════════════════════════════
   PUBLIC APP
   ════════════════════════════════════════════════════════════ */
function PublicApp() {
  useScrollReveal();

  const [form, setForm] = useState({
    name: "",
    email: "",
    phone: "",
    projectType: "Live VJing",
    budget: "Event consultation",
    message: "",
    audience: "",
    pillars: "",
    eventDate: "",
    venueAddress: "",
    screenSize: "",
    screenResolution: ""
  });
  const [status, setStatus] = useState({ type: "idle", text: "" });
  const [siteConfig, setSiteConfig] = useState({ recaptchaSiteKey: "" });
  const [recaptchaReady, setRecaptchaReady] = useState(false);
  const [verification, setVerification] = useState({
    email: createVerificationState(),
    phone: createVerificationState()
  });
  const [isContactOpen, setIsContactOpen] = useState(false);

  function openContact(event) {
    if (event) event.preventDefault();
    setIsContactOpen(true);
  }

  function closeContact() {
    setIsContactOpen(false);
  }

  /* Lock scroll & handle Escape key for modal */
  useEffect(() => {
    if (!isContactOpen) return;
    const originalOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    const handleKeyDown = (event) => {
      if (event.key === "Escape") {
        setIsContactOpen(false);
      }
    };
    window.addEventListener("keydown", handleKeyDown);
    return () => {
      document.body.style.overflow = originalOverflow;
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [isContactOpen]);

  /* Open modal if URL has hash #contact */
  useEffect(() => {
    const handleHash = () => {
      if (window.location.hash === "#contact") {
        setIsContactOpen(true);
      }
    };
    handleHash();
    window.addEventListener("hashchange", handleHash);
    return () => window.removeEventListener("hashchange", handleHash);
  }, []);

  /* Resend countdown */
  useEffect(() => {
    const timerId = window.setInterval(() => {
      const now = Date.now();
      setVerification((current) => {
        const next = { email: { ...current.email }, phone: { ...current.phone } };
        for (const channel of ["email", "phone"]) {
          const resendAt = next[channel].resendAvailableAtUtc;
          if (!resendAt) { next[channel].resendSecondsLeft = 0; continue; }
          const secondsLeft = Math.max(0, Math.ceil((new Date(resendAt).getTime() - now) / 1000));
          next[channel].resendSecondsLeft = secondsLeft;
        }
        return next;
      });
    }, 1000);
    return () => window.clearInterval(timerId);
  }, []);

  /* Config */
  useEffect(() => {
    let active = true;
    requestJson("/api/public-config")
      .then((config) => { if (active) setSiteConfig(config); })
      .catch(() => { if (active) setSiteConfig({ recaptchaSiteKey: "" }); });
    return () => { active = false; };
  }, []);

  /* reCAPTCHA */
  useEffect(() => {
    let active = true;
    if (!siteConfig.recaptchaSiteKey) { setRecaptchaReady(false); return undefined; }
    setRecaptchaReady(false);
    loadRecaptchaScript(siteConfig.recaptchaSiteKey)
      .then(() => {
        if (!active || !window.grecaptcha) return;
        window.grecaptcha.ready(() => { if (active) setRecaptchaReady(true); });
      })
      .catch(() => {
        if (active) setStatus({ type: "error", text: "reCAPTCHA could not load. Please refresh the page." });
      });
    return () => { active = false; setRecaptchaReady(false); };
  }, [siteConfig.recaptchaSiteKey]);

  /* Link verification from URL */
  useEffect(() => {
    const searchParams = new URLSearchParams(window.location.search);
    const verifyToken = searchParams.get("verifyToken");
    const verifyChannel = searchParams.get("verifyChannel");
    const verifyValue = searchParams.get("verifyValue");
    if (!verifyToken || !verifyChannel || !verifyValue) return;
    setIsContactOpen(true);
    const mappedChannel = verifyChannel.toLowerCase() === "phone" || verifyChannel.toLowerCase() === "mobile" ? "phone" : "email";
    setForm((current) => ({ ...current, [mappedChannel]: verifyValue }));
    setVerification((current) => ({
      ...current,
      [mappedChannel]: { ...current[mappedChannel], status: { type: "loading", text: "Confirming verification link..." } }
    }));
    requestJson("/api/verification/verify-link", {
      method: "POST",
      body: JSON.stringify({ channel: mappedChannel, value: verifyValue, token: verifyToken })
    })
      .then((response) => {
        setVerification((current) => ({
          ...current,
          [mappedChannel]: { ...current[mappedChannel], verificationId: response.verificationId, verified: true, status: { type: "success", text: "Verification link confirmed." } }
        }));
        const updated = new URL(window.location.href);
        updated.searchParams.delete("verifyToken");
        updated.searchParams.delete("verifyChannel");
        updated.searchParams.delete("verifyValue");
        window.history.replaceState({}, "", `${updated.pathname}${updated.search}${updated.hash}`);
      })
      .catch((error) => {
        setVerification((current) => ({
          ...current,
          [mappedChannel]: { ...current[mappedChannel], status: { type: "error", text: error.message || "Verification link is invalid or expired." } }
        }));
      });
  }, []);

  function updateField(event) {
    const { name, value } = event.target;
    setForm((current) => ({ ...current, [name]: value }));
    if (name === "email" || name === "phone") {
      setVerification((current) => ({ ...current, [name]: createVerificationState() }));
    }
  }

  function updateOtpField(channel, value) {
    setVerification((current) => ({ ...current, [channel]: { ...current[channel], otp: value } }));
  }

  async function sendOtp(channel) {
    const value = channel === "email" ? form.email : form.phone;
    const currentVerification = verification[channel];
    if (currentVerification.resendSecondsLeft > 0) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "error", text: `Please wait ${current[channel].resendSecondsLeft}s before requesting a new OTP.` } } }));
      return;
    }
    if (!value.trim()) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "error", text: channel === "email" ? "Enter your email first." : "Enter your phone number first." } } }));
      return;
    }
    setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "loading", text: "Sending OTP..." } } }));
    try {
      const response = await requestJson("/api/verification/send-otp", { method: "POST", body: JSON.stringify({ channel, value }) });
      setVerification((current) => ({
        ...current,
        [channel]: {
          ...current[channel],
          challengeId: response.challengeId,
          verificationId: "",
          verified: false,
          expiresAtUtc: response.expiresAtUtc,
          resendAvailableAtUtc: response.resendAvailableAtUtc,
          resendSecondsLeft: Math.max(0, Math.ceil((new Date(response.resendAvailableAtUtc).getTime() - Date.now()) / 1000)),
          developmentOtp: response.developmentOtp || "",
          status: { type: "success", text: "OTP sent. Enter the code to verify." }
        }
      }));
    } catch (error) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "error", text: error.message || "Unable to send OTP." } } }));
    }
  }

  async function verifyOtp(channel) {
    const value = channel === "email" ? form.email : form.phone;
    const currentVerification = verification[channel];
    if (!currentVerification.challengeId) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "error", text: "Request OTP first." } } }));
      return;
    }
    if (!currentVerification.otp.trim()) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "error", text: "Enter OTP to verify." } } }));
      return;
    }
    setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "loading", text: "Verifying OTP..." } } }));
    try {
      const response = await requestJson("/api/verification/verify-otp", {
        method: "POST",
        body: JSON.stringify({ channel, value, challengeId: currentVerification.challengeId, otp: currentVerification.otp })
      });
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], verificationId: response.verificationId, verified: true, status: { type: "success", text: "Verification complete." } } }));
    } catch (error) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], verified: false, verificationId: "", status: { type: "error", text: error.message || "OTP verification failed." } } }));
    }
  }

  async function fillAndVerifyOtp(channel, otpCode) {
    updateOtpField(channel, otpCode);
    const value = channel === "email" ? form.email : form.phone;
    const currentVerification = verification[channel];
    if (!currentVerification.challengeId) return;
    setVerification((current) => ({
      ...current,
      [channel]: { ...current[channel], otp: otpCode, status: { type: "loading", text: "Verifying code..." } }
    }));
    try {
      const response = await requestJson("/api/verification/verify-otp", {
        method: "POST",
        body: JSON.stringify({ channel, value, challengeId: currentVerification.challengeId, otp: otpCode })
      });
      setVerification((current) => ({
        ...current,
        [channel]: {
          ...current[channel],
          otp: otpCode,
          verificationId: response.verificationId,
          verified: true,
          status: { type: "success", text: "Verified successfully!" }
        }
      }));
    } catch (error) {
      setVerification((current) => ({
        ...current,
        [channel]: { ...current[channel], verified: false, verificationId: "", status: { type: "error", text: error.message || "OTP verification failed." } }
      }));
    }
  }

  async function sendVerificationLink(channel) {
    const value = channel === "email" ? form.email : form.phone;
    const currentVerification = verification[channel];
    if (currentVerification.resendSecondsLeft > 0) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "error", text: `Please wait ${current[channel].resendSecondsLeft}s before requesting another verification.` } } }));
      return;
    }
    if (!value.trim()) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "error", text: channel === "email" ? "Enter your email first." : "Enter your phone number first." } } }));
      return;
    }
    setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "loading", text: "Creating verification link..." } } }));
    try {
      const response = await requestJson("/api/verification/send-link", { method: "POST", body: JSON.stringify({ channel, value }) });
      setVerification((current) => ({
        ...current,
        [channel]: {
          ...current[channel],
          linkToken: response.token,
          resendAvailableAtUtc: response.resendAvailableAtUtc,
          resendSecondsLeft: Math.max(0, Math.ceil((new Date(response.resendAvailableAtUtc).getTime() - Date.now()) / 1000)),
          developmentLink: response.developmentVerificationLink || "",
          status: {
            type: "success",
            text: response.developmentVerificationLink
              ? "Verification link generated. Open the dev link below to confirm."
              : "Verification link generated and should be delivered to the user."
          }
        }
      }));
    } catch (error) {
      setVerification((current) => ({ ...current, [channel]: { ...current[channel], status: { type: "error", text: error.message || "Unable to generate verification link." } } }));
    }
  }

  async function createCaptchaToken() {
    if (!siteConfig.recaptchaSiteKey) return "";
    if (!window.grecaptcha) throw new Error("reCAPTCHA is not available yet. Please refresh and try again.");
    return window.grecaptcha.execute(siteConfig.recaptchaSiteKey, { action: "contact_submit" });
  }

  async function submitContact(event) {
    event.preventDefault();
    if (!verification.email.verified || !verification.email.verificationId) {
      setStatus({ type: "error", text: "Please verify your email using OTP before submitting." });
      return;
    }
    if (!verification.phone.verified || !verification.phone.verificationId) {
      setStatus({ type: "error", text: "Please verify your mobile number using OTP before submitting." });
      return;
    }
    if (siteConfig.recaptchaSiteKey && !recaptchaReady) {
      setStatus({ type: "error", text: "reCAPTCHA is still initializing. Please wait a moment and try again." });
      return;
    }
    setStatus({ type: "loading", text: "Sending your request..." });
    try {
      const captchaToken = await createCaptchaToken();
      await requestJson("/api/contact", {
        method: "POST",
        body: JSON.stringify({
          ...form,
          emailVerificationId: verification.email.verificationId,
          phoneVerificationId: verification.phone.verificationId,
          captchaToken
        })
      });
      setStatus({ type: "success", text: "Thanks. Your booking request was captured successfully." });
      setForm((current) => ({
        ...current,
        name: "", email: "", phone: "", message: "",
        audience: "", pillars: "", eventDate: "",
        venueAddress: "", screenSize: "", screenResolution: ""
      }));
      setVerification({ email: createVerificationState(), phone: createVerificationState() });
    } catch (error) {
      setStatus({ type: "error", text: error.message || "Please complete the form before sending." });
    }
  }

  /* ── JSX ── */
  return (
    <main className="vj-page">
      <section className="vj-shell hero-shell" id="home">
        <header className="top-nav reveal">
          <a className="brand" href="#home" aria-label="VJ Bean home">
            <img src="/logo-vjbean.svg" alt="VJ Bean logo" className="brand-logo" />
            <span className="brand-name">Visual Jockey</span>
          </a>
          <nav className="nav-links" aria-label="Main navigation">
            {navItems.map((item) => (
              <a
                key={item.href}
                href={item.href}
                onClick={item.href === "#contact" ? openContact : undefined}
              >
                {item.label}
              </a>
            ))}
          </nav>
          <a href="#contact" className="nav-cta" onClick={openContact}>Let's Connect</a>
        </header>

        <section className="hero-panel reveal reveal-delay-1">
          <div className="hero-left">
            <p className="hero-eyebrow">Visuals that move. Stories that stay.</p>
            <h1>
              I Create Visual Experiences That
              <span> Captivate and Inspire</span>
            </h1>
            <p>
              A visual jockey blending creativity, technology and rhythm to craft immersive live visual
              journeys for concerts, festivals, brands, and private events.
            </p>
            <div className="hero-actions">
              <a className="primary-button" href="#projects">Play Showreel</a>
              <a className="secondary-button" href="#projects">View My Work</a>
            </div>
          </div>
          <div className="hero-visual" role="img" aria-label="Live visual performance backdrop" />
        </section>

        <div className="stats-ribbon reveal reveal-delay-2">
          {heroStats.map((item) => (
            <article key={item.label}>
              <strong>{item.value}</strong>
              <span>{item.label}</span>
            </article>
          ))}
        </div>
      </section>

      <section className="vj-shell dashboard-grid" id="about">
        <article className="panel about-panel reveal">
          <div className="about-photo" aria-hidden="true" />
          <div>
            <p className="panel-label">About Me</p>
            <h2>Turning Ideas Into Powerful Visual Stories</h2>
            <p>
              I'm a Bangalore-based visual jockey focused on live motion design, stage mapping,
              and emotional storytelling through synchronized visuals.
            </p>
            <a href="#contact" className="mini-link" onClick={openContact}>Know More About Me</a>
          </div>
        </article>

        <div className="service-highlights">
          {serviceCards.map((service, idx) => (
            <article key={service.title} className={`panel mini-panel reveal reveal-delay-${idx + 1}`}>
              <div className="mini-icon">{service.icon}</div>
              <h3>{service.title}</h3>
              <p>{service.description}</p>
            </article>
          ))}
        </div>
      </section>

      <section className="vj-shell content-grid" id="experience">
        <article className="panel timeline-panel reveal">
          <p className="panel-label">Experience</p>
          <div className="timeline-list">
            {experienceTimeline.map((entry) => (
              <div key={entry.years} className="timeline-item">
                <span>{entry.years}</span>
                <h3>{entry.role}</h3>
                <p>{entry.detail}</p>
              </div>
            ))}
          </div>
        </article>

        <article className="panel skills-panel reveal reveal-delay-1" id="skills">
          <p className="panel-label">Skills</p>
          <div className="skills-list">
            {skillBars.map((skill) => (
              <div key={skill.name} className="skill-row">
                <header>
                  <span>{skill.name}</span>
                  <strong>{skill.percent}%</strong>
                </header>
                <div className="skill-track">
                  <span className={skill.className} />
                </div>
              </div>
            ))}
          </div>
        </article>

        <article className="panel projects-panel reveal reveal-delay-2" id="projects">
          <div className="panel-head">
            <p className="panel-label">Featured Projects</p>
            <a href="#contact" onClick={openContact}>View all projects</a>
          </div>
          <div className="project-tiles">
            {featureTiles.map((tile) => (
              <article key={tile.title} className={`project-tile ${tile.className}`}>
                <div>
                  <h3>{tile.title}</h3>
                  <span>{tile.subtitle}</span>
                </div>
              </article>
            ))}
          </div>
        </article>
      </section>

      <section className="vj-shell connect-cta-banner reveal reveal-delay-2" id="contact">
        <div className="cta-banner-content">
          <p className="panel-label">Let's Work Together</p>
          <h2>Have a Project in Mind?</h2>
          <p>
            Share event details and we'll get back quickly with creative direction and delivery options.
          </p>
        </div>
        <button type="button" className="primary-button cta-banner-btn" onClick={openContact}>
          <span>Let's Connect</span>
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <line x1="5" y1="12" x2="19" y2="12"></line>
            <polyline points="12 5 19 12 12 19"></polyline>
          </svg>
        </button>
      </section>

      <section className="vj-shell service-strip" id="services">
        {services.map((service, index) => (
          <span key={`${service}-${index}`}>{service}</span>
        ))}
      </section>

      <footer className="site-footer">
        <div className="footer-brand">
          <img src="/logo-vjbean.svg" alt="VJ Bean" className="footer-logo" />
          <div>
            <strong>Visual Jockey</strong>
            <p>Visuals that move. Stories that stay.</p>
          </div>
        </div>
        <div className="footer-links">
          <a href="#home">Home</a>
          <a href="#projects">Projects</a>
          <a href="#services">Services</a>
          <a href="#contact" onClick={openContact}>Contact</a>
          <a href="mailto:vjbean03@gmail.com" className="footer-email-link">vjbean03@gmail.com</a>
        </div>
        <p className="footer-copy">© {new Date().getFullYear()} Visual Jockey. All Rights Reserved.</p>
      </footer>

      {isContactOpen && (
        <div
          className="modal-overlay"
          onClick={closeContact}
          role="dialog"
          aria-modal="true"
          aria-labelledby="contact-modal-title"
        >
          <div className="modal-glow" aria-hidden="true" />
          <div className="modal-container" onClick={(e) => e.stopPropagation()}>
            <button
              type="button"
              className="modal-close"
              onClick={closeContact}
              aria-label="Close dialog"
            >
              <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
                <line x1="18" y1="6" x2="6" y2="18"></line>
                <line x1="6" y1="6" x2="18" y2="18"></line>
              </svg>
            </button>

            <div className="modal-scroll-area">
              <header className="modal-header">
                <div className="modal-badge">
                  <span className="modal-badge-dot" />
                  <span>Let's Work Together</span>
                </div>
                <h2 id="contact-modal-title">Have a Project in Mind?</h2>
                <p>Share event details and we'll get back quickly with creative direction and delivery options.</p>
              </header>

              <form className="compact-form modal-form" onSubmit={submitContact}>
                {/* Row 1: Name & Project Type */}
                <div className="form-row-2">
                  <div className="form-group">
                    <label className="form-label">
                      <span>Your Name <span className="req">*</span></span>
                    </label>
                    <input
                      name="name"
                      value={form.name}
                      onChange={updateField}
                      placeholder="e.g. Sateswara Sahu"
                      required
                    />
                  </div>

                  <div className="form-group">
                    <label className="form-label">
                      <span>Project / Event Type</span>
                    </label>
                    <select
                      name="budget"
                      value={form.budget}
                      onChange={updateField}
                      title="Project Type"
                      aria-label="Project Type"
                    >
                      <option value="Corporate Events">Corporate Events</option>
                      <option value="Wedding Events">Wedding Events</option>
                      <option value="Music Festival">Music Festival</option>
                      <option value="Club Show">Club Show</option>
                      <option value="Other event type">Other event type</option>
                    </select>
                  </div>
                </div>

                {/* Row 2: Email & Phone Verification */}
                <div className="form-row-2">
                  {/* Email Group */}
                  <div className="form-group">
                    <div className="field-header">
                      <label className="form-label">
                        <span>Email Address <span className="req">*</span></span>
                      </label>
                      {verification.email.verified && (
                        <span className="inline-verified-tag-static">✓ Verified</span>
                      )}
                    </div>

                    <div className="input-action-wrap">
                      <input
                        name="email"
                        type="email"
                        value={form.email}
                        onChange={updateField}
                        placeholder="name@example.com"
                        required
                      />
                      {!verification.email.verified && (
                        <button
                          type="button"
                          className="inline-action-btn"
                          onClick={() => sendOtp("email")}
                          disabled={verification.email.status.type === "loading" || verification.email.resendSecondsLeft > 0}
                        >
                          {verification.email.resendSecondsLeft > 0
                            ? `Wait ${verification.email.resendSecondsLeft}s`
                            : verification.email.challengeId ? "Resend" : "Send OTP"}
                        </button>
                      )}
                    </div>

                    {/* Collapsible OTP Tray for Email */}
                    {verification.email.challengeId && !verification.email.verified && (
                      <div className="otp-tray">
                        <div className="otp-tray-input">
                          <input
                            value={verification.email.otp}
                            onChange={(e) => updateOtpField("email", e.target.value)}
                            placeholder="Enter 6-digit OTP"
                            inputMode="numeric"
                            maxLength={8}
                          />
                          <button
                            type="button"
                            className="otp-verify-btn"
                            onClick={() => verifyOtp("email")}
                            disabled={verification.email.status.type === "loading"}
                          >
                            {verification.email.status.type === "loading" ? "..." : "Verify"}
                          </button>
                        </div>

                        {verification.email.developmentOtp && (
                          <button
                            type="button"
                            className="dev-otp-chip"
                            onClick={() => fillAndVerifyOtp("email", verification.email.developmentOtp)}
                            title="Click to auto-verify with dev OTP"
                          >
                            Dev: <strong>{verification.email.developmentOtp}</strong> (Auto-fill)
                          </button>
                        )}

                        <div className="otp-tray-footer">
                          <button
                            type="button"
                            className="link-btn"
                            onClick={() => sendVerificationLink("email")}
                            disabled={verification.email.status.type === "loading" || verification.email.resendSecondsLeft > 0}
                          >
                            Magic link?
                          </button>
                        </div>

                        {verification.email.developmentLink && (
                          <p className="form-status">
                            Dev: <a href={verification.email.developmentLink} target="_blank" rel="noopener noreferrer">Open link</a>
                          </p>
                        )}
                        {verification.email.status.text && (
                          <p className={`form-status ${verification.email.status.type}`}>{verification.email.status.text}</p>
                        )}
                      </div>
                    )}
                  </div>

                  {/* Phone Group */}
                  <div className="form-group">
                    <div className="field-header">
                      <label className="form-label">
                        <span>Phone Number <span className="req">*</span></span>
                      </label>
                      {verification.phone.verified && (
                        <span className="inline-verified-tag-static">✓ Verified</span>
                      )}
                    </div>

                    <div className="input-action-wrap">
                      <input
                        name="phone"
                        type="tel"
                        inputMode="tel"
                        value={form.phone}
                        onChange={updateField}
                        placeholder="+91 98765 43210"
                        required
                      />
                      {!verification.phone.verified && (
                        <button
                          type="button"
                          className="inline-action-btn"
                          onClick={() => sendOtp("phone")}
                          disabled={verification.phone.status.type === "loading" || verification.phone.resendSecondsLeft > 0}
                        >
                          {verification.phone.resendSecondsLeft > 0
                            ? `Wait ${verification.phone.resendSecondsLeft}s`
                            : verification.phone.challengeId ? "Resend" : "Send OTP"}
                        </button>
                      )}
                    </div>

                    {/* Collapsible OTP Tray for Phone */}
                    {verification.phone.challengeId && !verification.phone.verified && (
                      <div className="otp-tray">
                        <div className="otp-tray-input">
                          <input
                            value={verification.phone.otp}
                            onChange={(e) => updateOtpField("phone", e.target.value)}
                            placeholder="Enter Mobile OTP"
                            inputMode="numeric"
                            maxLength={8}
                          />
                          <button
                            type="button"
                            className="otp-verify-btn"
                            onClick={() => verifyOtp("phone")}
                            disabled={verification.phone.status.type === "loading"}
                          >
                            {verification.phone.status.type === "loading" ? "..." : "Verify"}
                          </button>
                        </div>

                        {verification.phone.developmentOtp && (
                          <button
                            type="button"
                            className="dev-otp-chip"
                            onClick={() => fillAndVerifyOtp("phone", verification.phone.developmentOtp)}
                            title="Click to auto-verify with dev OTP"
                          >
                            Dev: <strong>{verification.phone.developmentOtp}</strong> (Auto-fill)
                          </button>
                        )}

                        <div className="otp-tray-footer">
                          <button
                            type="button"
                            className="link-btn"
                            onClick={() => sendVerificationLink("phone")}
                            disabled={verification.phone.status.type === "loading" || verification.phone.resendSecondsLeft > 0}
                          >
                            Magic link?
                          </button>
                        </div>

                        {verification.phone.developmentLink && (
                          <p className="form-status">
                            Dev: <a href={verification.phone.developmentLink} target="_blank" rel="noopener noreferrer">Open link</a>
                          </p>
                        )}
                        {verification.phone.status.text && (
                          <p className={`form-status ${verification.phone.status.type}`}>{verification.phone.status.text}</p>
                        )}
                      </div>
                    )}
                  </div>
                </div>

                {/* Row 3: Event Date & Venue Location */}
                <div className="form-row-2">
                  <div className="form-group">
                    <label className="form-label">
                      <span>Event Date</span>
                    </label>
                    <input
                      name="eventDate"
                      type="date"
                      value={form.eventDate}
                      onChange={updateField}
                      title="Event Date"
                      aria-label="Event Date"
                    />
                  </div>

                  <div className="form-group">
                    <label className="form-label">
                      <span>Venue Location / City</span>
                    </label>
                    <input
                      name="venueAddress"
                      value={form.venueAddress}
                      onChange={updateField}
                      placeholder="e.g. Palace Grounds, Bangalore"
                    />
                  </div>
                </div>

                {/* Row 4: Message */}
                <div className="form-group">
                  <label className="form-label">
                    <span>Your Message / Event Vision</span>
                  </label>
                  <textarea
                    name="message"
                    value={form.message}
                    onChange={updateField}
                    rows={2}
                    placeholder="Tell us about the screens, stage setup, visual style, or schedule..."
                  />
                </div>

                {/* Row 5: Action Footer Bar with reCAPTCHA & Submit */}
                <div className="modal-footer-bar">
                  <div className="captcha-inline">
                    {siteConfig.recaptchaSiteKey ? (
                      <span className="captcha-text">
                        🔒 reCAPTCHA protected{recaptchaReady ? " (Ready)" : " (Initializing...)"}
                      </span>
                    ) : (
                      <span className="captcha-text">🔒 Secure Request</span>
                    )}
                  </div>

                  <button type="submit" className="modal-submit-btn" disabled={status.type === "loading"}>
                    {status.type === "loading" ? "Sending..." : "Send Request ✦"}
                  </button>
                </div>
                {status.text && <p className={`form-status ${status.type}`}>{status.text}</p>}
              </form>
            </div>
          </div>
        </div>
      )}
    </main>
  );
}

/* ════════════════════════════════════════════════════════════
   ADMIN APP — full functionality preserved
   ════════════════════════════════════════════════════════════ */
function AdminApp() {
  const [session, setSession] = useState({ loading: true, authenticated: false, userName: "" });
  const [loginForm, setLoginForm] = useState({ username: "", password: "" });
  const [loginStatus, setLoginStatus] = useState({ type: "idle", text: "" });
  const [dashboard, setDashboard] = useState(null);
  const [dashboardStatus, setDashboardStatus] = useState({ type: "idle", text: "" });
  const [activeSection, setActiveSection] = useState("requests");

  useEffect(() => {
    document.title = "VJ BEAN | Admin";
  }, []);

  useEffect(() => {
    let active = true;
    requestJson("/api/admin/session")
      .then((data) => {
        if (!active) return;
        setSession({ loading: false, authenticated: data.authenticated, userName: data.userName || "" });
      })
      .catch(() => {
        if (active) setSession({ loading: false, authenticated: false, userName: "" });
      });
    return () => { active = false; };
  }, []);

  useEffect(() => {
    if (!session.authenticated) return;
    let active = true;
    setDashboardStatus({ type: "loading", text: "Loading dashboard..." });
    requestJson("/api/admin/dashboard")
      .then((data) => { if (active) { setDashboard(data); setDashboardStatus({ type: "idle", text: "" }); } })
      .catch((error) => { if (active) setDashboardStatus({ type: "error", text: error.message || "Unable to load dashboard." }); });
    return () => { active = false; };
  }, [session.authenticated]);

  function updateLoginField(event) {
    const { name, value } = event.target;
    setLoginForm((current) => ({ ...current, [name]: value }));
  }

  async function submitLogin(event) {
    event.preventDefault();
    setLoginStatus({ type: "loading", text: "Signing in..." });
    try {
      await requestJson("/api/admin/login", { method: "POST", body: JSON.stringify(loginForm) });
      setSession({ loading: false, authenticated: true, userName: loginForm.username });
      setLoginStatus({ type: "success", text: "Signed in successfully." });
      setLoginForm((current) => ({ ...current, password: "" }));
    } catch (error) {
      setLoginStatus({ type: "error", text: error.message || "Unable to sign in." });
    }
  }

  async function logout() {
    await requestJson("/api/admin/logout", { method: "POST" });
    setSession({ loading: false, authenticated: false, userName: "" });
    setDashboard(null);
    setActiveSection("requests");
  }

  if (session.loading) {
    return <main className="admin-loading">Loading admin console…</main>;
  }

  if (!session.authenticated) {
    return (
      <main className="admin-auth-shell">
        <section className="admin-auth-card">
          <p className="eyebrow">Admin console</p>
          <h1>Sign in to review requests, visitors, activity, and errors.</h1>
          <form onSubmit={submitLogin} className="admin-auth-form">
            <label>
              Username
              <input name="username" value={loginForm.username} onChange={updateLoginField} required />
            </label>
            <label>
              Password
              <input name="password" type="password" value={loginForm.password} onChange={updateLoginField} required />
            </label>
            <button className="primary-button full" disabled={loginStatus.type === "loading"}>
              Sign in
            </button>
            {loginStatus.text && <p className={`form-status ${loginStatus.type}`}>{loginStatus.text}</p>}
          </form>
        </section>
      </main>
    );
  }

  const sections = [
    { key: "requests", label: "Requests Received" },
    { key: "visitors", label: "Visitors & Location" },
    { key: "activity", label: "Activity Log" },
    { key: "errors", label: "Error Log" }
  ];

  return (
    <main className="admin-shell">
      <aside className="admin-sidebar">
        <div>
          <p className="eyebrow">Admin console</p>
          <h1>VJ BEAN</h1>
          <p className="admin-meta">Signed in as {session.userName}</p>
        </div>
        <nav className="admin-nav">
          {sections.map((section) => (
            <button
              key={section.key}
              type="button"
              className={section.key === activeSection ? "admin-nav-item active" : "admin-nav-item"}
              onClick={() => setActiveSection(section.key)}
            >
              {section.label}
            </button>
          ))}
        </nav>
        <button type="button" className="secondary-button admin-logout" onClick={logout}>Sign out</button>
      </aside>

      <section className="admin-main">
        <header className="admin-header">
          <div>
            <p className="eyebrow">Dashboard</p>
            <h2>Website activity at a glance</h2>
          </div>
          <button type="button" className="secondary-button" onClick={() => requestJson("/api/admin/dashboard").then(setDashboard)}>
            Refresh
          </button>
        </header>

        {dashboardStatus.text && <p className={`form-status ${dashboardStatus.type}`}>{dashboardStatus.text}</p>}

        <div className="admin-stats">
          <article><strong>{dashboard?.totalRequests ?? 0}</strong><span>Requests</span></article>
          <article><strong>{dashboard?.totalVisits ?? 0}</strong><span>Visits</span></article>
          <article><strong>{dashboard?.uniqueVisitors ?? 0}</strong><span>Unique IPs</span></article>
          <article><strong>{dashboard?.totalErrors ?? 0}</strong><span>Errors</span></article>
        </div>

        {activeSection === "requests" && (
          <div className="admin-panel">
            <h3>Requests Received</h3>
            <div className="table-wrap">
              <table>
                <thead>
                  <tr>
                    <th>When</th><th>Name</th><th>Email</th><th>Email verified</th>
                    <th>Phone</th><th>Mobile verified</th><th>Need</th><th>Event type</th>
                    <th>Audience</th><th>Pillars</th><th>Event date</th><th>Venue address</th>
                    <th>Screen size</th><th>Screen resolution</th><th>IP</th><th>Location</th><th>Details</th>
                  </tr>
                </thead>
                <tbody>
                  {(dashboard?.requests ?? []).map((item) => (
                    <tr key={item.id}>
                      <td>{formatDateTime(item.submittedAtUtc)}</td>
                      <td>{item.name}</td>
                      <td>{item.email}</td>
                      <td>{item.emailVerified ? "Yes" : "No"}</td>
                      <td>{item.phone}</td>
                      <td>{item.phoneVerified ? "Yes" : "No"}</td>
                      <td>{item.projectType}</td>
                      <td>{item.budget}</td>
                      <td>{item.audience || "-"}</td>
                      <td>{item.pillars || "-"}</td>
                      <td>{item.eventDate || "-"}</td>
                      <td>{item.venueAddress || "-"}</td>
                      <td>{item.screenSize || "-"}</td>
                      <td>{item.screenResolution || "-"}</td>
                      <td>{item.ipAddress}</td>
                      <td>{item.location}</td>
                      <td>{item.message}</td>
                    </tr>
                  ))}
                  {(dashboard?.requests ?? []).length === 0 && (
                    <tr><td colSpan="17">No booking requests have been received yet.</td></tr>
                  )}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {activeSection === "visitors" && (
          <div className="admin-panel">
            <h3>Visitors and locations</h3>
            <div className="location-grid">
              {(dashboard?.topLocations ?? []).map((location) => (
                <article key={location.location}>
                  <strong>{location.count}</strong>
                  <span>{location.location}</span>
                </article>
              ))}
            </div>
            <div className="table-wrap">
              <table>
                <thead>
                  <tr><th>When</th><th>Path</th><th>Method</th><th>IP</th><th>Location</th><th>User agent</th></tr>
                </thead>
                <tbody>
                  {(dashboard?.visits ?? []).map((visit) => (
                    <tr key={visit.id}>
                      <td>{formatDateTime(visit.visitedAtUtc)}</td>
                      <td>{visit.path}</td>
                      <td>{visit.method}</td>
                      <td>{visit.ipAddress}</td>
                      <td>{visit.location}</td>
                      <td>{visit.userAgent}</td>
                    </tr>
                  ))}
                  {(dashboard?.visits ?? []).length === 0 && (
                    <tr><td colSpan="6">No visitor activity has been recorded yet.</td></tr>
                  )}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {activeSection === "activity" && (
          <div className="admin-panel">
            <h3>Activity log</h3>
            <div className="table-wrap">
              <table>
                <thead>
                  <tr><th>When</th><th>Category</th><th>Message</th><th>Path</th><th>IP</th><th>Location</th></tr>
                </thead>
                <tbody>
                  {(dashboard?.activity ?? []).map((entry) => (
                    <tr key={entry.id}>
                      <td>{formatDateTime(entry.occurredAtUtc)}</td>
                      <td>{entry.category}</td>
                      <td>{entry.message}</td>
                      <td>{entry.path}</td>
                      <td>{entry.ipAddress}</td>
                      <td>{entry.location}</td>
                    </tr>
                  ))}
                  {(dashboard?.activity ?? []).length === 0 && (
                    <tr><td colSpan="6">No activity has been recorded yet.</td></tr>
                  )}
                </tbody>
              </table>
            </div>
          </div>
        )}

        {activeSection === "errors" && (
          <div className="admin-panel">
            <h3>Error log</h3>
            <div className="table-wrap">
              <table>
                <thead>
                  <tr><th>When</th><th>Message</th><th>Path</th><th>IP</th><th>Location</th><th>Details</th></tr>
                </thead>
                <tbody>
                  {(dashboard?.errors ?? []).map((entry) => (
                    <tr key={entry.id}>
                      <td>{formatDateTime(entry.occurredAtUtc)}</td>
                      <td>{entry.message}</td>
                      <td>{entry.path}</td>
                      <td>{entry.ipAddress}</td>
                      <td>{entry.location}</td>
                      <td>{entry.details}</td>
                    </tr>
                  ))}
                  {(dashboard?.errors ?? []).length === 0 && (
                    <tr><td colSpan="6">No errors have been recorded yet.</td></tr>
                  )}
                </tbody>
              </table>
            </div>
          </div>
        )}
      </section>
    </main>
  );
}

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