// Product data + static content
const PRODUCTS = [
  {
    id: "used-car-dealership",
    slug: "used-car-dealership",
    // Tebex Headless package ID — set this from your Tebex Creator Panel.
    tebexPackageId: 7402025,
    // Tebex package requires a `discord_id` option — buyer must link their
    // Discord before checkout. handleCheckout enforces this and passes the
    // ID through as a basket variable.
    requiresDiscord: true,
    name: "Used Car Dealership",
    resourceName: "nd_usedcar",
    tagline: "Player-opened open world lots with auctions, raffles, offer system & a full management tablet",
    price: 29.99,
    currency: "USD",
    status: "live",
    category: "Economy",
    version: "1.0.0",
    updated: "2026-04-21",
    highlights: [
      "In-world DUI vehicle cards with hold-to-buy UX",
      "Full dealership management through an in-game tablet",
      "Fixed-price, auction, raffle, and custom-offer sale modes",
      "Employee system with configurable grades and permissions",
      "In-game admin wizard — new dealership live in under 5 minutes",
      "QBX, QB-Core, and ESX bridge out of the box",
    ],
    longDesc:
      "A full used dealership system for FiveM where players own lots, manage employees, and sell vehicles through fixed-price listings, custom offers, timed auctions, or ticketed raffles with a live leaderboard. Admins stand up a new dealership from an in-game wizard in under five minutes — very little config edits, no resource restart.",
    features: [
      { icon: "Car",     title: "In-world vehicle cards", desc: "Walk up to any car on a lot and a 3D DUI shows its model, condition, performance upgrades, asking price, and if not fixed price, a live auction timer. Hold E to buy, G to send a counter-offer." },
      { icon: "Users",   title: "Player-owned dealerships", desc: "Ownable lots ship with a custom employee hierarchy, granular permissions, society banking, a per-lot consignment fee, a revenue dashboard, and a full transaction log — not just a deed." },
      { icon: "Sliders", title: "Flexible sale modes", desc: "Per lot: direct sale, employee-approval queue, or employee-on-duty gating. Buyers can also send counter-offers on any listing the lot allows. Switch modes live from the tablet." },
      { icon: "Gavel",   title: "Timed auctions", desc: "English-style with anti-snipe extension and a hard duration cap. Live bid sync, outbid alerts, seller reclaim on no-bid, and automatic claim-window handling." },
      { icon: "Sync",    title: "Ticketed raffles", desc: "Set a ticket price and duration, players enter up to a per-raffle cap, and the winner is drawn weighted by tickets held. Unclaimed wins auto-garage after the claim window." },
      { icon: "Shield",  title: "In-game admin wizard", desc: "/dealeradmin walks you through placing the lot center, parking spots, sell zone, and pickup spot with on-screen markers. Edit allowed vehicle classes, blacklists, and fees without ever touching a file." },
    ],
    requirements: [
      ["Framework", "QBX / QB-Core / ESX (bridge)"],
      ["FiveM build", "2545+"],
      ["Database", "oxmysql 2.7+"],
      ["Dependencies", "ox_lib, oxmysql"],
    ],
    compatibility: [
      {
        name: "JG Advanced Garages",
        resourceName: "jg_advancedgarages",
        note: "Stored vehicles sync into JG's garage system out of the box.",
      },
    ],
    gallery: [
      { label: "Showcase",          caption: "Script showcase",                 type: "video", youtubeId: "UxEuTIVHXMo" },
      { label: "Display tab",       caption: "Dealership management tablet",    src: "assets/screenshots/tablet-display-1.png" },
      { label: "Full display",      caption: "Live display spots with vehicles", src: "assets/screenshots/tablet-display-full.png" },
      { label: "Auction",           caption: "In-world auction prompt",          src: "assets/screenshots/auction-prompt.png" },
      { label: "Raffle",            caption: "Ticketed raffles",                 src: "assets/screenshots/raffle-prompt.png" },
      { label: "Purchase offer",    caption: "Offers from dealerships",          src: "assets/screenshots/purchase-offer.png" },
      { label: "Team",              caption: "Staff, grades & permissions",      src: "assets/screenshots/tablet-team.png" },
      { label: "Admin",             caption: "Admin: multi-dealer management",   src: "assets/screenshots/admin-dealerships.png" },
      { label: "Store prompt",      caption: "Store vehicle prompt",             src: "assets/screenshots/store-vehicle-prompt.png" },
      { label: "Vehicle notes",     caption: "Seller notes on lots",             src: "assets/screenshots/faggio-note.png" },
      { label: "Liveries",          caption: "Full livery support on display",   src: "assets/screenshots/baller-livery.png" },
    ],
  },

  // ───────────────────────────────────────────────────────────────────────
  // COMING SOON (paid). These render full product cards + preview detail
  // pages but are gated: `status: "coming-soon"` disables Add to cart / Buy
  // everywhere (ProductCard, ProductPage, and addToCart in app.jsx) and they
  // can't enter the Tebex basket. To launch one: fill in real copy + gallery,
  // add its `tebexPackageId`, set version/updated, and flip status to "live".
  // Placeholder copy below — rename / replace with your real upcoming scripts.
  // ───────────────────────────────────────────────────────────────────────
  {
    id: "fleet-insurance",
    slug: "fleet-insurance",
    tebexPackageId: null,        // set when live
    requiresDiscord: true,
    name: "Fleet Insurance",
    resourceName: "nd_fleetinsurance",
    tagline: "Per-vehicle coverage, claims, and premiums that make crashing actually cost something.",
    price: 24.99,
    currency: "USD",
    status: "coming-soon",
    category: "Economy",
    version: null,
    updated: null,
    comingSoonNote: "in development",
    highlights: [
      "Per-vehicle policies with tiered coverage and deductibles",
      "Automatic claim payouts on insured-vehicle destruction",
      "Premium billing tied to driving history / claim frequency",
      "Broker job + player-run agencies",
      "QBX, QB-Core, and ESX bridge out of the box",
    ],
    longDesc:
      "A full vehicle insurance system for FiveM — players insure their cars, pay recurring premiums, and file claims when a vehicle is destroyed. Designed to give the economy real stakes around vehicle loss. Full details and showcase drop with the public release.",
    gallery: [
      { type: "video", caption: "Showcase coming soon" },
    ],
  },
  {
    id: "tow-contracts",
    slug: "tow-contracts",
    tebexPackageId: null,        // set when live
    requiresDiscord: true,
    name: "Tow Contracts",
    resourceName: "nd_towcontracts",
    tagline: "Dynamic tow jobs, impound contracts, and a dispatch board for player-run tow companies.",
    price: 19.99,
    currency: "USD",
    status: "coming-soon",
    category: "Economy",
    version: null,
    updated: null,
    comingSoonNote: "planning",
    highlights: [
      "Dynamic tow requests from a live dispatch board",
      "Impound contracts with city / PD integration",
      "Player-owned tow companies with employees and payouts",
      "Per-contract pricing, distance bonuses, and reputation",
      "QBX, QB-Core, and ESX bridge out of the box",
    ],
    longDesc:
      "A contract-driven towing system for FiveM where players run tow companies, accept dispatch jobs, and handle impounds for the city. Full details and showcase drop with the public release.",
    gallery: [
      { type: "video", caption: "Showcase coming soon" },
    ],
  },
];

const FREE_PRODUCTS = [
  {
    id: "multijob",
    slug: "multijob",
    name: "Multijob",
    resourceName: "nd_multijob",
    tagline: "Hold and switch between multiple jobs without re-hiring or paying a dev $20.",
    category: "Jobs",
    githubUrl: "https://github.com/NateDoggDev/nd_multijob",
    frameworks: ["QBX", "QB-Core", "ESX"],
    longDesc:
      "A clean multijob menu for FiveM that lets players hold and switch between multiple jobs without re-hiring, logging out, or paying a dev $20 for the privilege. Works on qb-core, qbx_core, and esx.",
    gallery: [
      {
        kind: "video",
        src: "assets/videos/multijob-demo.mp4",
        poster: "assets/screenshots/multijob-menu.png",
        label: "Demo",
        caption: "Switching jobs · F6 menu",
      },
      {
        kind: "image",
        src: "assets/screenshots/multijob-menu.png",
        label: "Menu",
        caption: "F6 menu — active job at top, switch list below",
      },
    ],
    howItWorks: [
      "Press F6 — your active job sits at the top with rank, pay, and an on/off duty toggle. Below it is your switch list.",
      "Click any other job to swap to it instantly, or hit the leave button to quit (with a confirm so you don't fat-finger your career).",
      "Hires, fires, and promotions from boss menus or other resources update the menu live.",
      "Players can drag the menu to wherever they like and the position is saved per-player.",
    ],
    support: "Happy to provide support — open a ticket in the Discord.",
  },
];

// Lightweight, further-out teasers (no detail page). Fleet Insurance and Tow
// Contracts graduated to full coming-soon PRODUCTS above; this is for concepts
// that aren't ready for a preview page yet.
const COMING_SOON = [
  { id: "cs-3", name: "Import Brokerage", note: "Concept" },
];

const FEATURED_ID = "used-car-dealership";

// Static reference rates vs USD. These are approximate display-only values;
// Tebex does the authoritative conversion at checkout.
const CURRENCIES = [
  { code: "USD", symbol: "$",  rate: 1.00,   locale: "en-US", label: "US Dollar" },
  { code: "EUR", symbol: "€",  rate: 0.92,   locale: "de-DE", label: "Euro" },
  { code: "GBP", symbol: "£",  rate: 0.78,   locale: "en-GB", label: "British Pound" },
  { code: "CAD", symbol: "C$", rate: 1.37,   locale: "en-CA", label: "Canadian Dollar" },
  { code: "AUD", symbol: "A$", rate: 1.52,   locale: "en-AU", label: "Australian Dollar" },
  { code: "BRL", symbol: "R$", rate: 5.05,   locale: "pt-BR", label: "Brazilian Real" },
  { code: "MXN", symbol: "MX$",rate: 17.20,  locale: "es-MX", label: "Mexican Peso" },
  { code: "SEK", symbol: "kr", rate: 10.50,  locale: "sv-SE", label: "Swedish Krona" },
  { code: "PLN", symbol: "zł", rate: 3.95,   locale: "pl-PL", label: "Polish Złoty" },
  { code: "JPY", symbol: "¥",  rate: 155,    locale: "ja-JP", label: "Japanese Yen" },
];

function getCurrency(code) {
  return CURRENCIES.find((c) => c.code === code) || CURRENCIES[0];
}

// True for live, buyable products. Coming-soon (or ANY non-"live" status —
// 'beta', 'archived', etc.) items must never be priced, carted, or sent to
// Tebex. Single source of truth shared by the cart guard (app.jsx addToCart),
// the localStorage rehydration filter, cartTotal, and the home live/planned
// counts, so those predicates can't drift apart.
function isLive(p) {
  return !!p && (!p.status || p.status === "live");
}

function formatPrice(n, cur = "USD") {
  const c = getCurrency(cur);
  const converted = n * c.rate;
  try {
    return new Intl.NumberFormat(c.locale, {
      style: "currency",
      currency: c.code,
      minimumFractionDigits: c.code === "JPY" ? 0 : 2,
      maximumFractionDigits: c.code === "JPY" ? 0 : 2,
    }).format(converted);
  } catch {
    return c.symbol + converted.toFixed(c.code === "JPY" ? 0 : 2);
  }
}

Object.assign(window, { PRODUCTS, FREE_PRODUCTS, COMING_SOON, FEATURED_ID, CURRENCIES, getCurrency, formatPrice, isLive });
