(() => {
  "use strict";

  const nativeFetch = window.fetch.bind(window);
  const pathParts = location.pathname.split("/").filter(Boolean);
  const configuredAppId = document.documentElement?.dataset?.apuStandaloneProject || window.__APU_STANDALONE__?.slug || "";
  const appId = configuredAppId || (pathParts[0] === "projects" ? (pathParts[1] || "") : (pathParts[0] || ""));
  const now = () => new Date().toISOString();

  const read = (key, fallback) => {
    try {
      const value = JSON.parse(localStorage.getItem(key));
      return Array.isArray(fallback) ? (Array.isArray(value) ? value : fallback) : (value ?? fallback);
    } catch {
      return fallback;
    }
  };
  const write = (key, value) => {
    localStorage.setItem(key, JSON.stringify(value));
    return value;
  };
  const json = (value, status = 200) =>
    Promise.resolve(new Response(JSON.stringify(value), {
      status,
      headers: { "Content-Type": "application/json", "Cache-Control": "no-store" }
    }));

  const incidentSeed = [
    {id:1,service_name:"Payment Gateway",incident_time:"2026-06-12T10:30:00",duration_minutes:45,severity:"critical",priority:"p1",status:"resolved",responsible_team:"Payment Team",root_cause:"Connection pool exhausted during transaction spike",impact:"Payment completion temporarily unavailable",resolution_note:"Expanded pool and added circuit breaker",recovery_result:"Transactions restored",uptime_percentage:98.9,downtime_minutes:45,created_at:now(),updated_at:now()},
    {id:2,service_name:"Authentication",incident_time:"2026-06-10T14:15:00",duration_minutes:20,severity:"high",priority:"p2",status:"resolved",responsible_team:"Security Team",root_cause:"Token validation memory leak",impact:"Users could not sign in",resolution_note:"Service restarted and patched",recovery_result:"Normal access restored",uptime_percentage:99.5,downtime_minutes:20,created_at:now(),updated_at:now()},
    {id:3,service_name:"Data Pipeline",incident_time:"2026-06-08T03:00:00",duration_minutes:90,severity:"critical",priority:"p1",status:"monitoring",responsible_team:"Data Team",root_cause:"Disk capacity reached",impact:"Analytics refresh delayed",resolution_note:"Logs rotated and storage expanded",recovery_result:"Backlog processing",uptime_percentage:99.0,downtime_minutes:90,created_at:now(),updated_at:now()},
    {id:4,service_name:"CDN Service",incident_time:"2026-06-06T11:00:00",duration_minutes:30,severity:"medium",priority:"p3",status:"investigating",responsible_team:"Frontend Team",root_cause:"Cache invalidation issue",impact:"Stale content in several regions",resolution_note:"Manual purge completed",recovery_result:"Monitoring propagation",uptime_percentage:99.7,downtime_minutes:30,created_at:now(),updated_at:now()},
    {id:5,service_name:"Mobile Push",incident_time:"2026-06-03T19:00:00",duration_minutes:10,severity:"low",priority:"p4",status:"open",responsible_team:"Mobile Team",root_cause:"Certificate renewal pending",impact:"Push delivery delayed",resolution_note:"Renewal in progress",recovery_result:"Pending",uptime_percentage:99.9,downtime_minutes:10,created_at:now(),updated_at:now()}
  ];

  const ticketSeed = [
    {id:1,ticketId:"TKT-001",title:"Laptop cannot connect to VPN",description:"Remote employee receives timeout",status:"open",priority:"high",category:"Network",division:"Finance",requesterName:"Alya Putri",requesterEmail:"alya@example.com",assignedTo:"Network Support",slaHours:8,resolutionNotes:"",createdAt:now(),updatedAt:now()},
    {id:2,ticketId:"TKT-002",title:"Email client synchronization issue",description:"Inbox stops updating intermittently",status:"in_progress",priority:"medium",category:"Software",division:"Operations",requesterName:"Rizky Aditya",requesterEmail:"rizky@example.com",assignedTo:"Application Support",slaHours:24,resolutionNotes:"Cache reset scheduled",createdAt:now(),updatedAt:now()},
    {id:3,ticketId:"TKT-003",title:"Printer toner and queue error",description:"Shared printer queue remains paused",status:"resolved",priority:"low",category:"Hardware",division:"HR",requesterName:"Nadia Sari",requesterEmail:"nadia@example.com",assignedTo:"IT Support",slaHours:48,resolutionNotes:"Queue rebuilt and toner replaced",createdAt:now(),updatedAt:now()}
  ];
  const assetSeed = [
    {id:1,assetId:"AST-001",name:"Dell Latitude 7440",category:"laptop",status:"active",serialNumber:"DL7440-001",purchaseDate:"2025-01-12",warrantyExpiry:"2028-01-12",assignedTo:"Alya Putri",department:"Finance",location:"Jakarta HQ",licenseKey:"",licenseExpiry:"",notes:"Corporate laptop",createdAt:now(),updatedAt:now()},
    {id:2,assetId:"AST-002",name:"Cisco Catalyst Switch",category:"network",status:"active",serialNumber:"CSW-2201",purchaseDate:"2024-08-02",warrantyExpiry:"2027-08-02",assignedTo:"Network Team",department:"IT",location:"Server Room",licenseKey:"",licenseExpiry:"",notes:"Core access switch",createdAt:now(),updatedAt:now()},
    {id:3,assetId:"AST-003",name:"HP LaserJet Pro",category:"printer",status:"maintenance",serialNumber:"HP-LJ-883",purchaseDate:"2023-04-18",warrantyExpiry:"2026-04-18",assignedTo:"HR Shared",department:"HR",location:"Floor 3",licenseKey:"",licenseExpiry:"",notes:"Scheduled maintenance",createdAt:now(),updatedAt:now()}
  ];
  const linkSeed = [
    {id:1,originalUrl:"https://developer.mozilla.org/en-US/docs/Web/Progressive_web_apps",customAlias:"mdn-pwa",category:"training",owner:"Engineering",campaignName:"Knowledge Base",expiryDate:"",accessStatus:"active",clickCount:284,createdAt:now()},
    {id:2,originalUrl:"https://developers.cloudflare.com/pages/",customAlias:"cloudflare-pages",category:"product",owner:"Cloud Team",campaignName:"Deployment",expiryDate:"",accessStatus:"active",clickCount:196,createdAt:now()},
    {id:3,originalUrl:"https://github.com/yirassssindaba-coder",customAlias:"portfolio-github",category:"external",owner:"Portfolio",campaignName:"Professional Profile",expiryDate:"",accessStatus:"active",clickCount:145,createdAt:now()}
  ];

  const metrics = (items) => {
    const countBy = (key) => items.reduce((acc, item) => {
      const value = item[key] || "unknown";
      acc[value] = (acc[value] || 0) + 1;
      return acc;
    }, {});
    const average = (key) => items.length
      ? items.reduce((sum, item) => sum + Number(item[key] || 0), 0) / items.length
      : 0;
    const monthCounts = Array.from({length:12}, (_, index) => ({
      month:index + 1,
      count:items.filter(item => new Date(item.incident_time).getMonth() === index).length
    }));
    const severity = countBy("severity");
    const status = countBy("status");
    return {
      total_incidents:items.length,
      open_incidents:status.open || 0,
      resolved_incidents:status.resolved || 0,
      avg_duration_minutes:Number(average("duration_minutes").toFixed(1)),
      avg_uptime_percentage:Number(average("uptime_percentage").toFixed(2)),
      critical_count:severity.critical || 0,
      high_count:severity.high || 0,
      medium_count:severity.medium || 0,
      low_count:severity.low || 0,
      severity_breakdown:severity,
      status_breakdown:status,
      team_breakdown:countBy("responsible_team"),
      monthly_trend:monthCounts
    };
  };

  // Malaysia Cost of Living — complete static data and finite-number calculator.
  // All values are planning estimates in MYR and are intentionally labeled as demo data.
  const malaysiaCities = [
    { id: "kuala-lumpur", name: "Kuala Lumpur" },
    { id: "johor-bahru", name: "Johor Bahru" },
    { id: "george-town", name: "George Town" },
    { id: "cyberjaya", name: "Cyberjaya" },
    { id: "malacca-city", name: "Malacca City" }
  ];

  const malaysiaCampuses = {
    "kuala-lumpur": [
      { id: "um", name: "Universiti Malaya" },
      { id: "utm-kl", name: "UTM Kuala Lumpur" },
      { id: "apu", name: "Asia Pacific University" }
    ],
    "johor-bahru": [
      { id: "utm-skudai", name: "UTM Johor Bahru / Skudai" }
    ],
    "george-town": [
      { id: "usm", name: "Universiti Sains Malaysia" }
    ],
    "cyberjaya": [
      { id: "mmu-cyberjaya", name: "Multimedia University" },
      { id: "limkokwing", name: "Limkokwing University" }
    ],
    "malacca-city": [
      { id: "mmu-melaka", name: "Multimedia University Melaka" },
      { id: "utem", name: "Universiti Teknikal Malaysia Melaka" }
    ]
  };

  const malaysiaProfiles = {
    "kuala-lumpur": {
      name: "Kuala Lumpur", affordabilityScore: 58,
      normal: { Housing: 1200, Food: 750, Transport: 250, Utilities: 180, "Internet & Mobile": 90, "Study & Supplies": 120, Healthcare: 90, "Personal & Leisure": 320 },
      housing: { "shared-room": 950, studio: 1750, "one-bedroom": 2300, "two-bedroom": 3200 }
    },
    "johor-bahru": {
      name: "Johor Bahru", affordabilityScore: 78,
      normal: { Housing: 820, Food: 620, Transport: 190, Utilities: 150, "Internet & Mobile": 80, "Study & Supplies": 110, Healthcare: 80, "Personal & Leisure": 280 },
      housing: { "shared-room": 650, studio: 1150, "one-bedroom": 1500, "two-bedroom": 2200 }
    },
    "george-town": {
      name: "George Town", affordabilityScore: 72,
      normal: { Housing: 900, Food: 660, Transport: 180, Utilities: 155, "Internet & Mobile": 80, "Study & Supplies": 110, Healthcare: 85, "Personal & Leisure": 300 },
      housing: { "shared-room": 720, studio: 1250, "one-bedroom": 1650, "two-bedroom": 2350 }
    },
    "cyberjaya": {
      name: "Cyberjaya", affordabilityScore: 68,
      normal: { Housing: 980, Food: 640, Transport: 230, Utilities: 165, "Internet & Mobile": 90, "Study & Supplies": 115, Healthcare: 85, "Personal & Leisure": 300 },
      housing: { "shared-room": 780, studio: 1350, "one-bedroom": 1800, "two-bedroom": 2550 }
    },
    "malacca-city": {
      name: "Malacca City", affordabilityScore: 84,
      normal: { Housing: 700, Food: 560, Transport: 160, Utilities: 135, "Internet & Mobile": 75, "Study & Supplies": 100, Healthcare: 75, "Personal & Leisure": 245 },
      housing: { "shared-room": 540, studio: 950, "one-bedroom": 1250, "two-bedroom": 1850 }
    }
  };

  const malaysiaHousingAreas = [
    { id:"kl-bangsar", cityId:"kuala-lumpur", areaName:"Bangsar", areaType:"urban", avgRentShared:1200, avgRentStudio:2200, avgRentOneRoom:2900, distanceToCampusKm:4.8, safetyRating:4, transportOptions:["LRT","Bus","Grab"], pros:["Excellent transit access","Many shops and services"], cons:["Higher rent","Busy at peak hours"] },
    { id:"kl-setapak", cityId:"kuala-lumpur", areaName:"Setapak", areaType:"student-area", avgRentShared:780, avgRentStudio:1450, avgRentOneRoom:1900, distanceToCampusKm:3.2, safetyRating:4, transportOptions:["LRT","Bus"], pros:["Student-friendly pricing","Wide food selection"], cons:["Traffic congestion","Variable building quality"] },
    { id:"kl-cheras", cityId:"kuala-lumpur", areaName:"Cheras", areaType:"suburban", avgRentShared:700, avgRentStudio:1300, avgRentOneRoom:1750, distanceToCampusKm:8.5, safetyRating:4, transportOptions:["MRT","Bus"], pros:["Good value","MRT coverage"], cons:["Longer commute to central KL","Some areas are car-oriented"] },

    { id:"jb-skudai", cityId:"johor-bahru", areaName:"Skudai", areaType:"student-area", avgRentShared:520, avgRentStudio:900, avgRentOneRoom:1200, distanceToCampusKm:2.5, safetyRating:4, transportOptions:["Bus","Campus Shuttle","Grab"], pros:["Close to UTM","Affordable student services"], cons:["Limited rail transit","Peak-hour traffic"] },
    { id:"jb-taman-universiti", cityId:"johor-bahru", areaName:"Taman Universiti", areaType:"student-area", avgRentShared:580, avgRentStudio:980, avgRentOneRoom:1300, distanceToCampusKm:3.8, safetyRating:4, transportOptions:["Bus","Grab"], pros:["Many eateries","Strong student community"], cons:["Can be noisy","Parking can be limited"] },
    { id:"jb-city-centre", cityId:"johor-bahru", areaName:"JB City Centre", areaType:"urban", avgRentShared:850, avgRentStudio:1450, avgRentOneRoom:1900, distanceToCampusKm:18, safetyRating:4, transportOptions:["Bus","Train","Grab"], pros:["Near major services","Cross-border connectivity"], cons:["Farther from UTM","Higher rent"] },

    { id:"pg-gelugor", cityId:"george-town", areaName:"Gelugor", areaType:"student-area", avgRentShared:620, avgRentStudio:1100, avgRentOneRoom:1450, distanceToCampusKm:2.2, safetyRating:4, transportOptions:["Bus","Grab"], pros:["Near USM","Affordable food"], cons:["Traffic at class hours","Older housing stock"] },
    { id:"pg-jelutong", cityId:"george-town", areaName:"Jelutong", areaType:"urban", avgRentShared:720, avgRentStudio:1250, avgRentOneRoom:1650, distanceToCampusKm:6.5, safetyRating:4, transportOptions:["Bus","Grab"], pros:["Central location","Strong local amenities"], cons:["Dense neighborhood","Limited parking"] },
    { id:"pg-tanjung-tokong", cityId:"george-town", areaName:"Tanjung Tokong", areaType:"coastal", avgRentShared:950, avgRentStudio:1650, avgRentOneRoom:2200, distanceToCampusKm:12, safetyRating:5, transportOptions:["Bus","Grab"], pros:["Modern residences","Coastal amenities"], cons:["Premium pricing","Longer campus commute"] },

    { id:"cyb-tamarind", cityId:"cyberjaya", areaName:"Tamarind Square", areaType:"tech-district", avgRentShared:820, avgRentStudio:1400, avgRentOneRoom:1850, distanceToCampusKm:3.5, safetyRating:5, transportOptions:["Bus","MRT Feeder","Grab"], pros:["Modern facilities","Good study environment"], cons:["Car-oriented layout","Higher café prices"] },
    { id:"cyb-cyberia", cityId:"cyberjaya", areaName:"Cyberia", areaType:"student-area", avgRentShared:650, avgRentStudio:1100, avgRentOneRoom:1450, distanceToCampusKm:1.8, safetyRating:4, transportOptions:["Campus Shuttle","Bus","Grab"], pros:["Close to MMU","Student-focused rentals"], cons:["Older units vary in quality","Limited late-night transit"] },
    { id:"cyb-serin", cityId:"cyberjaya", areaName:"Serin Residency", areaType:"residential", avgRentShared:760, avgRentStudio:1300, avgRentOneRoom:1750, distanceToCampusKm:4.6, safetyRating:5, transportOptions:["Bus","Grab"], pros:["Quiet environment","Good facilities"], cons:["Grocery trips may require transport","Less walkable"] },

    { id:"mel-bukit-beruang", cityId:"malacca-city", areaName:"Bukit Beruang", areaType:"student-area", avgRentShared:450, avgRentStudio:800, avgRentOneRoom:1050, distanceToCampusKm:2.0, safetyRating:4, transportOptions:["Bus","Grab"], pros:["Close to MMU Melaka","Low monthly rent"], cons:["Limited public transit frequency","Fewer premium amenities"] },
    { id:"mel-ayer-keroh", cityId:"malacca-city", areaName:"Ayer Keroh", areaType:"suburban", avgRentShared:520, avgRentStudio:900, avgRentOneRoom:1200, distanceToCampusKm:6.5, safetyRating:5, transportOptions:["Bus","Grab"], pros:["Calm residential environment","Close to education district"], cons:["Less walkable","Evening transport can be limited"] },
    { id:"mel-city-centre", cityId:"malacca-city", areaName:"Melaka City Centre", areaType:"heritage-urban", avgRentShared:680, avgRentStudio:1150, avgRentOneRoom:1500, distanceToCampusKm:9.0, safetyRating:4, transportOptions:["Bus","Grab"], pros:["Many attractions and services","Good food access"], cons:["Tourist-season congestion","Higher central rent"] }
  ];

  const finite = (value, fallback = 0) => {
    const number = Number(value);
    return Number.isFinite(number) ? number : fallback;
  };
  const roundMoney = value => Math.max(0, Math.round(finite(value)));
  const sumValues = object => Object.values(object).reduce((sum, value) => sum + finite(value), 0);

  function malaysiaCostCategories(cityId) {
    const ids = malaysiaProfiles[cityId] ? [cityId] : Object.keys(malaysiaProfiles);
    const names = Object.keys(malaysiaProfiles[ids[0]].normal);
    return names.map(category => {
      const normal = ids.reduce((sum, id) => sum + malaysiaProfiles[id].normal[category], 0) / ids.length;
      return {
        category,
        minimumMyr: roundMoney(normal * 0.74),
        normalMyr: roundMoney(normal),
        safeMyr: roundMoney(normal * 1.32)
      };
    });
  }

  function malaysiaCostPayload(cityId) {
    const categories = malaysiaCostCategories(cityId);
    return {
      cityId: malaysiaProfiles[cityId] ? cityId : null,
      cityName: malaysiaProfiles[cityId]?.name || null,
      categories,
      totalMinimum: categories.reduce((sum, item) => sum + item.minimumMyr, 0),
      totalNormal: categories.reduce((sum, item) => sum + item.normalMyr, 0),
      totalSafe: categories.reduce((sum, item) => sum + item.safeMyr, 0)
    };
  }

  function malaysiaBudgetCalculation(payload = {}) {
    const cityId = malaysiaProfiles[payload.cityId] ? payload.cityId : malaysiaCities[0].id;
    const profile = malaysiaProfiles[cityId];
    const familySize = Math.min(6, Math.max(1, Math.round(finite(payload.familySize, 1))));
    const housingType = profile.housing[payload.housingType] ? payload.housingType : "shared-room";
    const level = payload.lifestyleLevel === "minimum" ? "minimum" : payload.lifestyleLevel === "comfortable" || payload.lifestyleLevel === "safe" ? "comfortable" : "normal";
    const factor = level === "minimum" ? 0.76 : level === "comfortable" ? 1.30 : 1;
    const normal = profile.normal;
    const housing = roundMoney(profile.housing[housingType] * (level === "minimum" ? 0.92 : level === "comfortable" ? 1.12 : 1));
    const food = roundMoney(normal.Food * factor * Math.pow(familySize, 0.88));
    const transport = roundMoney(normal.Transport * factor * Math.max(1, familySize * 0.72));
    const utilities = roundMoney(normal.Utilities * factor * (0.72 + familySize * 0.28));
    const internet = roundMoney(normal["Internet & Mobile"] * (0.8 + familySize * 0.35));
    const study = roundMoney(normal["Study & Supplies"] * factor * Math.max(1, familySize * 0.65));
    const healthcare = roundMoney(normal.Healthcare * factor * familySize);
    const personal = roundMoney(normal["Personal & Leisure"] * factor * familySize);
    const rawItems = [
      ["Housing", housing], ["Food", food], ["Transport", transport], ["Utilities", utilities],
      ["Internet & Mobile", internet], ["Study & Supplies", study], ["Healthcare", healthcare], ["Personal & Leisure", personal]
    ];
    const subtotal = rawItems.reduce((sum, item) => sum + item[1], 0);
    const includeEmergencyBuffer = payload.includeEmergencyBuffer !== false;
    const emergencyBuffer = includeEmergencyBuffer ? roundMoney(subtotal * 0.10) : 0;
    const totalMonthly = subtotal + emergencyBuffer;
    const scholarship = Math.max(0, finite(payload.scholarshipAmount, 0));
    const lineItems = rawItems.map(([category, amountMyr]) => ({
      category,
      amountMyr,
      percentage: totalMonthly > 0 ? Number(((amountMyr / totalMonthly) * 100).toFixed(1)) : 0
    }));
    if (emergencyBuffer > 0) lineItems.push({ category:"Emergency Buffer", amountMyr:emergencyBuffer, percentage:Number(((emergencyBuffer / totalMonthly) * 100).toFixed(1)) });
    return {
      cityId,
      cityName: profile.name,
      housingType,
      lifestyleLevel: level,
      familySize,
      totalMonthly,
      totalYearly: totalMonthly * 12,
      emergencyBuffer,
      scholarshipCoverage: scholarship > 0 && totalMonthly > 0 ? Number(((scholarship / totalMonthly) * 100).toFixed(1)) : 0,
      surplusOrDeficit: roundMoney(scholarship) - totalMonthly,
      lineItems,
      notes: [
        `Planning estimate for ${profile.name}; actual prices vary by property, contract, and lifestyle.`,
        `Calculation uses ${familySize} person${familySize > 1 ? "s" : ""}, ${housingType.replaceAll("-", " ")} housing, and the ${level} lifestyle tier.`,
        includeEmergencyBuffer ? "A 10% emergency buffer is included." : "Emergency buffer is not included."
      ]
    };
  }


  async function mockApi(input, options = {}) {
    const requestUrl = typeof input === "string" ? input : input.url;
    const url = new URL(requestUrl, location.origin);
    if (!url.pathname.startsWith("/api/")) return null;
    const method = (options.method || (typeof input !== "string" && input.method) || "GET").toUpperCase();
    let body = {};
    try { body = options.body ? JSON.parse(options.body) : {}; } catch {}

    if (appId === "malaysia-cost") {
      if (url.pathname === "/api/cities" && method === "GET") return json(malaysiaCities);

      const campusMatch = url.pathname.match(/^\/api\/cities\/([^/]+)\/campuses$/);
      if (campusMatch && method === "GET") return json(malaysiaCampuses[campusMatch[1]] || []);

      if (url.pathname === "/api/costs" && method === "GET") {
        return json(malaysiaCostPayload(url.searchParams.get("cityId") || ""));
      }

      if (url.pathname === "/api/costs/comparison" && method === "GET") {
        return json(malaysiaCities.map(city => {
          const cost = malaysiaCostPayload(city.id);
          return { cityId:city.id, cityName:city.name, totalNormal:cost.totalNormal, totalMinimum:cost.totalMinimum, totalSafe:cost.totalSafe };
        }));
      }

      if (url.pathname === "/api/housing/affordability" && method === "GET") {
        const cityId = url.searchParams.get("cityId");
        const ids = malaysiaProfiles[cityId] ? [cityId] : malaysiaCities.map(city => city.id);
        return json(ids.map(id => ({ cityId:id, cityName:malaysiaProfiles[id].name, affordabilityScore:malaysiaProfiles[id].affordabilityScore })));
      }

      if (url.pathname === "/api/housing/areas" && method === "GET") {
        const cityId = url.searchParams.get("cityId");
        return json(cityId ? malaysiaHousingAreas.filter(area => area.cityId === cityId) : malaysiaHousingAreas);
      }

      if (url.pathname === "/api/simulator/budget" && method === "POST") {
        return json(malaysiaBudgetCalculation(body));
      }

      if (url.pathname === "/api/simulator/sensitivity" && method === "POST") {
        const basePayload = {
          cityId:body.cityId,
          housingType:body.baseHousingType,
          lifestyleLevel:body.baseLifestyleLevel,
          familySize:body.familySize,
          includeEmergencyBuffer:true,
          scholarshipAmount:0
        };
        const base = malaysiaBudgetCalculation(basePayload);
        const profile = malaysiaProfiles[base.cityId];
        const rent = profile.housing[base.housingType] || profile.housing["shared-room"];
        const food = base.lineItems.find(item => item.category === "Food")?.amountMyr || 0;
        const transport = base.lineItems.find(item => item.category === "Transport")?.amountMyr || 0;
        const makeScenario = (variable, amount, percent) => ({
          variable,
          lowTotal:roundMoney(base.totalMonthly - amount * (finite(percent) / 100)),
          baseTotal:base.totalMonthly,
          highTotal:roundMoney(base.totalMonthly + amount * (finite(percent) / 100))
        });
        return json({ scenarios:[
          makeScenario("Rent", rent, body.rentVariationPercent || 20),
          makeScenario("Food", food, body.foodVariationPercent || 15),
          makeScenario("Transport", transport, body.transportVariationPercent || 10)
        ] });
      }

      if (url.pathname === "/api/analysis/summary" && method === "GET") {
        const costs = malaysiaCities.map(city => malaysiaCostPayload(city.id));
        const normalAverage = costs.reduce((sum, item) => sum + item.totalNormal, 0) / costs.length;
        const cheapest = costs.reduce((best, item) => item.totalNormal < best.totalNormal ? item : best, costs[0]);
        const averageHousing = malaysiaCities.reduce((sum, city) => sum + malaysiaProfiles[city.id].normal.Housing, 0) / malaysiaCities.length;
        return json({
          avgMonthlyBudgetNormal:roundMoney(normalAverage),
          mostAffordableCity:cheapest.cityName,
          mostAffordableCityBudget:cheapest.totalNormal,
          avgRentPct:Number(((averageHousing / normalAverage) * 100).toFixed(1)),
          scholarshipBenchmarkMyr:roundMoney(normalAverage * 1.15),
          dataSource:"Static planning dataset assembled from public cost categories and student-budget patterns; values are illustrative and not real-time quotations.",
          collectionPeriod:"Planning baseline for 2026",
          currencyNote:"All amounts are Malaysian Ringgit (MYR) per month unless stated otherwise.",
          citiesIncluded:malaysiaCities.map(city => city.name),
          methodology:"Category totals are calculated from housing, food, transport, utilities, connectivity, study supplies, healthcare, and personal spending. Minimum and safe tiers use consistent multipliers, while the simulator adjusts household size, housing type, lifestyle tier, and emergency reserves.",
          datasetInstructions:"Use the simulator for scenario planning, then verify accommodation contracts, university fees, transport, insurance, and current market prices before making a financial commitment.",
          limitations:["Market prices change by neighborhood and season.","Tuition, visa, flights, deposits, and one-time setup costs are excluded.","Family and medical needs can materially change the estimate."],
          disclaimer:"This application is an educational planning tool, not a quotation or financial guarantee."
        });
      }

      if (url.pathname === "/api/analysis/recommendations" && method === "GET") {
        const cityId = url.searchParams.get("cityId") || "johor-bahru";
        const tier = url.searchParams.get("budgetTier") || "normal";
        const cityName = malaysiaProfiles[cityId]?.name || "your selected city";
        return json([
          { id:"housing", category:"housing", impact:"high", title:"Keep housing below one third of the monthly plan", description:`Compare shared rooms and student neighborhoods in ${cityName} before signing a long lease.`, myrSavingEstimate:tier === "safe" ? 650 : 400 },
          { id:"transport", category:"transport", impact:"medium", title:"Choose housing near campus or reliable transit", description:"A slightly higher rent can still reduce total spending when daily transport and commute time are lower.", myrSavingEstimate:150 },
          { id:"buffer", category:"planning", impact:"medium", title:"Maintain an emergency reserve", description:"Keep at least one month of essential costs outside the routine spending budget.", myrSavingEstimate:null }
        ]);
      }
    }

    if (appId === "incident-monitoring") {
      let incidents = read("apu.incidents", incidentSeed);
      if (url.pathname === "/api/metrics" && method === "GET") return json(metrics(incidents));
      if (url.pathname === "/api/incidents" && method === "GET") {
        const status = url.searchParams.get("status");
        const severity = url.searchParams.get("severity");
        const service = (url.searchParams.get("service_name") || "").toLowerCase();
        let data = incidents.filter(item =>
          (!status || item.status === status) &&
          (!severity || item.severity === severity) &&
          (!service || item.service_name.toLowerCase().includes(service))
        );
        const limit = Number(url.searchParams.get("limit") || 100);
        return json(data.slice(0, limit));
      }
      if (url.pathname === "/api/incidents" && method === "POST") {
        const item = {...body,id:Math.max(0,...incidents.map(x=>x.id))+1,created_at:now(),updated_at:now()};
        write("apu.incidents", [item, ...incidents]);
        return json(item, 201);
      }
      const match = url.pathname.match(/^\/api\/incidents\/(\d+)$/);
      if (match) {
        const id = Number(match[1]);
        if (method === "DELETE") {
          write("apu.incidents", incidents.filter(x => x.id !== id));
          return json({message:"Incident deleted successfully"});
        }
        if (method === "PUT" || method === "PATCH") {
          let updated;
          incidents = incidents.map(x => x.id === id ? (updated={...x,...body,id,updated_at:now()}) : x);
          write("apu.incidents", incidents);
          return json(updated || {error:"Not found"}, updated ? 200 : 404);
        }
        return json(incidents.find(x => x.id === id) || {error:"Not found"}, incidents.some(x => x.id === id) ? 200 : 404);
      }
    }

    if (appId === "it-helpdesk") {
      const type = url.pathname.startsWith("/api/assets") ? "assets" : "tickets";
      const seed = type === "assets" ? assetSeed : ticketSeed;
      const key = `apu.${type}`;
      let items = read(key, seed);
      const match = url.pathname.match(new RegExp(`^/api/${type}/(\\d+)$`));
      if (url.pathname === `/api/${type}` && method === "GET") return json(items);
      if (url.pathname === `/api/${type}` && method === "POST") {
        const id = Math.max(0,...items.map(x=>x.id))+1;
        const prefix = type === "assets" ? "AST" : "TKT";
        const item = {
          ...body,id,
          [type === "assets" ? "assetId" : "ticketId"]:`${prefix}-${String(id).padStart(3,"0")}`,
          createdAt:now(),updatedAt:now()
        };
        write(key,[item,...items]);
        return json(item,201);
      }
      if (match) {
        const id=Number(match[1]);
        if (method === "DELETE") {
          write(key,items.filter(x=>x.id!==id));
          return json({success:true});
        }
        if (method === "PUT" || method === "PATCH") {
          let updated;
          items=items.map(x=>x.id===id?(updated={...x,...body,id,updatedAt:now()}):x);
          write(key,items);
          return json(updated || {error:"Not found"}, updated?200:404);
        }
      }
    }

    if (appId === "url-shortener") {
      let links = read("apu.links", linkSeed);
      if (url.pathname === "/api/links" && method === "GET") return json(links);
      if (url.pathname === "/api/links" && method === "POST") {
        if (body.url && !body.originalUrl) {
          const id = Math.max(0,...links.map(x=>x.id))+1;
          return json({original_url:body.url,short_url:id});
        }
        const duplicate = body.customAlias && links.some(x => x.customAlias === body.customAlias);
        if (duplicate) return json({message:"Alias already exists"},409);
        const id = Math.max(0,...links.map(x=>x.id))+1;
        const item={id,clickCount:0,createdAt:now(),accessStatus:"active",...body};
        write("apu.links",[item,...links]);
        return json(item,201);
      }
      const match=url.pathname.match(/^\/api\/links\/(\d+)$/);
      if(match){
        const id=Number(match[1]);
        if(method==="DELETE"){
          write("apu.links",links.filter(x=>x.id!==id));
          return json({success:true});
        }
        if(method==="PATCH"||method==="PUT"){
          let updated;
          links=links.map(x=>x.id===id?(updated={...x,...body,id}):x);
          write("apu.links",links);
          return json(updated||{message:"Not found"},updated?200:404);
        }
      }
    }


    if (appId === "ai-architect") {
      const aiDocs = read("apu.aiArchitect.documents", [
        {id:"doc-001",name:"AI Strategy 2025.pdf",type:"pdf",size:2400000,uploadedAt:"2025-05-01T10:00:00Z",status:"indexed",chunks:42},
        {id:"doc-002",name:"Cloud Architecture Guide.docx",type:"docx",size:890000,uploadedAt:"2025-05-03T14:30:00Z",status:"indexed",chunks:28},
        {id:"doc-003",name:"Enterprise Security Policy.pdf",type:"pdf",size:1200000,uploadedAt:"2025-05-05T09:15:00Z",status:"indexed",chunks:35},
        {id:"doc-004",name:"MLOps Best Practices.md",type:"md",size:150000,uploadedAt:"2025-05-06T11:45:00Z",status:"processing",chunks:0}
      ]);
      const metrics = {
        latencyP50:48,latencyP99:168,requestsPerHour:13742,errorRate:1.42,
        driftScore:.21,accuracy:.932,predictionCount:2918460,
        trend:Array.from({length:24},(_,i)=>({hour:`${String(i).padStart(2,"0")}:00`,requests:860+((i*137)%520),errors:4+((i*7)%18)}))
      };
      const versions = [
        {id:"mv-001",name:"Churn Predictor",version:"v2.4.1",status:"production",deployedAt:"2025-04-15T10:00:00Z",accuracy:.924,canRollback:false},
        {id:"mv-002",name:"Churn Predictor",version:"v2.3.0",status:"staging",deployedAt:"2025-03-20T09:00:00Z",accuracy:.911,canRollback:true},
        {id:"mv-003",name:"Sales Forecast",version:"v1.8.0",status:"production",deployedAt:"2025-04-01T11:00:00Z",accuracy:.887,canRollback:false},
        {id:"mv-004",name:"Loan Risk",version:"v3.1.2",status:"production",deployedAt:"2025-04-28T14:00:00Z",accuracy:.956,canRollback:false}
      ];
      const alerts = [
        {id:"alt-001",type:"drift",severity:"warning",message:"Feature distribution drift detected.",triggeredAt:"2025-05-10T06:15:00Z",resolved:false},
        {id:"alt-002",type:"latency",severity:"critical",message:"P99 latency exceeded the SLA.",triggeredAt:"2025-05-10T07:42:00Z",resolved:false},
        {id:"alt-003",type:"accuracy",severity:"info",message:"Accuracy is being monitored for 24 hours.",triggeredAt:"2025-05-09T22:00:00Z",resolved:false}
      ];
      const tickets = read("apu.aiArchitect.tickets", [
        {id:"TKT-1001",customerName:"Acme Corp",message:"Cannot login to the analytics dashboard.",status:"open",intent:"authentication",confidence:.94,recommendation:"Reset the SSO session.",escalated:false,createdAt:"2025-05-10T08:15:00Z"},
        {id:"TKT-1002",customerName:"Northwind",message:"Prediction API returns a timeout.",status:"in_progress",intent:"technical",confidence:.91,recommendation:"Scale inference replicas.",escalated:true,createdAt:"2025-05-09T14:22:00Z"}
      ]);
      const models = [
        {id:"churn-v24",name:"Customer Churn Predictor",type:"churn",version:"2.4.1",accuracy:.924,f1Score:.918,description:"Predicts churn risk from engagement signals.",trainedAt:"2025-04-12T00:00:00Z"},
        {id:"sales-v18",name:"Sales Forecast",type:"sales_forecast",version:"1.8.0",accuracy:.887,f1Score:.874,description:"Forecasts regional sales.",trainedAt:"2025-03-26T00:00:00Z"},
        {id:"loan-v31",name:"Loan Risk Assessment",type:"loan_risk",version:"3.1.2",accuracy:.956,f1Score:.948,description:"Estimates repayment risk.",trainedAt:"2025-04-22T00:00:00Z"}
      ];
      const blueprints = [
        {id:"bp-rag",title:"Enterprise RAG Platform",category:"Knowledge AI",description:"Grounded document Q&A with hybrid retrieval and citations.",problemStatement:"Knowledge is fragmented.",proposedArchitecture:"Portal, API gateway, ingestion, vector search, reranker, and governed LLM.",dataFlow:["Ingest","Embed","Retrieve","Rerank","Generate"],securityConsiderations:["RBAC","PII redaction","Prompt filters"],costEstimate:"$900–$2,400/month",deploymentPlan:["Pilot","Review","Production"],components:["Ingestion","Vector DB","LLM gateway","Evaluation","Observability"],businessValue:"Faster traceable knowledge retrieval."},
        {id:"bp-support",title:"AI Customer Support",category:"Automation",description:"Intent classification and human escalation.",problemStatement:"Support queues need faster triage.",proposedArchitecture:"Ticket API, classifier, retrieval, workflow engine, and console.",dataFlow:["Receive","Classify","Retrieve","Recommend","Escalate"],securityConsiderations:["PII minimization","Audit log","Human approval"],costEstimate:"$500–$1,500/month",deploymentPlan:["Shadow mode","Assist","Automation"],components:["Intent model","Knowledge base","Workflow engine","Dashboard"],businessValue:"Faster and more consistent support."},
        {id:"bp-mlops",title:"Production MLOps Pipeline",category:"MLOps",description:"Versioning, monitoring, drift detection, and rollout.",problemStatement:"Models degrade without controls.",proposedArchitecture:"Registry, CI/CD, monitoring, validation, and rollback.",dataFlow:["Train","Validate","Register","Deploy","Monitor"],securityConsiderations:["Signed artifacts","Least privilege","Approval"],costEstimate:"$700–$2,000/month",deploymentPlan:["Registry","Monitoring","Retraining"],components:["Registry","CI/CD","Drift monitor","Feature store"],businessValue:"Reliable model delivery."}
      ];
      const candidates = [
        {id:"cand-001",name:"Roberto O. T. Laksmana",role:"AI Solutions Architect",skills:["React","TypeScript","RAG","MLOps","Cloud Architecture","AI Governance"],experience:3,location:"Indonesia",education:"Informatics Management",matchScore:92},
        {id:"cand-002",name:"Alya Pratama",role:"Machine Learning Engineer",skills:["Python","FastAPI","PyTorch","MLflow","Docker"],experience:4,location:"Malaysia",education:"Computer Science",matchScore:86}
      ];
      const history = read("apu.aiArchitect.workflows", [
        {workflowId:"WF-1001",task:"Analyze support backlog",status:"completed",startedAt:"2025-05-10T06:00:00Z",completedAt:"2025-05-10T06:00:08Z",stepsCount:4}
      ]);
      const presets = [
        {id:"preset-startup",name:"Startup Pilot",description:"Small controlled pilot.",config:{userCount:100,requestsPerDay:5000,cloudProvider:"aws",tier:"low_cost"}},
        {id:"preset-growth",name:"Growth Platform",description:"Growing production workload.",config:{userCount:1200,requestsPerDay:80000,cloudProvider:"azure",tier:"standard"}},
        {id:"preset-enterprise",name:"Enterprise AI Scale",description:"High availability and governance.",config:{userCount:5000,requestsPerDay:500000,cloudProvider:"gcp",tier:"enterprise"}}
      ];
      const criteria = ["Compute","Storage","Managed Database","API Gateway","Model Serving","LLM Access","Vector Database","Monitoring","Security & Compliance","Scalability","Governance Tools","Cost (Lower = Better)","Vendor Lock-in Risk","Developer Experience"];
      const scoreRows = {
        aws:[92,95,88,91,90,85,80,88,94,96,82,75,60,85],
        azure:[88,90,91,86,87,96,85,86,92,90,88,78,62,84],
        gcp:[90,88,86,84,92,94,90,91,88,94,85,82,65,88]
      };
      const cloud = {
        providers:[
          {id:"aws",name:"Amazon Web Services",logo:"AWS",overallScore:87},
          {id:"azure",name:"Microsoft Azure",logo:"Azure",overallScore:88},
          {id:"gcp",name:"Google Cloud",logo:"GCP",overallScore:89}
        ],
        criteria,
        scores:Object.fromEntries(Object.entries(scoreRows).map(([key,row])=>[key,Object.fromEntries(criteria.map((c,i)=>[c,row[i]]))]))
      };
      const risks = [
        {id:"risk-001",title:"LLM Hallucination",category:"Reliability",severity:"high",likelihood:"medium",status:"mitigated",owner:"AI Engineering Lead",mitigationPlan:"RAG grounding, citations, and human escalation."},
        {id:"risk-002",title:"Training Data Privacy",category:"Privacy",severity:"critical",likelihood:"low",status:"monitoring",owner:"Chief Privacy Officer",mitigationPlan:"Anonymization and PII audits."},
        {id:"risk-003",title:"Model Bias",category:"Fairness",severity:"high",likelihood:"medium",status:"open",owner:"Responsible AI Lead",mitigationPlan:"Fairness evaluation and human review."}
      ];
      const incidents = [
        {id:"inc-001",title:"Churn Model Accuracy Drop",severity:"high",status:"resolved",reportedAt:"2025-04-15T11:22:00Z",resolvedAt:"2025-04-15T16:45:00Z",description:"Accuracy declined after a schema change.",affectedModel:"churn-v2.3.1"},
        {id:"inc-002",title:"Bias Detected in Loan Risk Model",severity:"high",status:"open",reportedAt:"2025-05-08T10:00:00Z",resolvedAt:null,description:"Fairness variance detected.",affectedModel:"loan-v3.1.2"}
      ];

      if (url.pathname === "/api/healthz" && method === "GET") return json({status:"ok",version:"static-2026.2",uptime:99.99});
      if (url.pathname === "/api/metrics" && method === "GET") return json(metrics);
      if (url.pathname === "/api/model-version" && method === "GET") return json(versions);
      if (url.pathname === "/api/alerts" && method === "GET") return json(alerts);

      if (url.pathname === "/api/documents" && method === "GET") return json(aiDocs);
      if (url.pathname === "/api/documents" && method === "POST") {
        const item={id:`doc-${Date.now()}`,name:body.name||"Uploaded Document",type:body.type||"txt",size:(body.content||"").length*2,uploadedAt:now(),status:"indexed",chunks:8};
        write("apu.aiArchitect.documents",[item,...aiDocs]); return json(item,201);
      }
      const docMatch=url.pathname.match(/^\/api\/documents\/([^/]+)$/);
      if (docMatch && method === "GET") {
        const base=aiDocs.find(x=>x.id===docMatch[1])||aiDocs[0];
        return json({...base,pages:8,author:"AI Architecture Office",wordCount:4200,readingTime:21,language:"English",summary:"Enterprise AI architecture covering retrieval, observability, security, and governance.",keyPoints:["Ground responses with trusted sources","Monitor accuracy, drift, latency, and cost","Apply least privilege","Keep human approval for critical decisions"],extractedPages:[{page:1,title:"Executive Summary",content:"A secure and measurable approach to enterprise AI delivery."},{page:3,title:"Architecture",content:"Ingestion, retrieval, model serving, observability, and governance."}]});
      }
      if (url.pathname === "/api/chat" && method === "POST") return json({answer:`Static RAG demo response for: "${body.message||"your question"}". Use hybrid retrieval, citations, confidence thresholds, and human escalation.`,sources:["AI Strategy 2025.pdf §3","Security Policy.pdf §4"],confidence:.91,sessionId:"static-session"});

      if (url.pathname === "/api/tickets" && method === "GET") return json(tickets);
      if (url.pathname === "/api/tickets" && method === "POST") {
        const item={id:`TKT-${Date.now().toString().slice(-5)}`,customerName:body.customerName||"Demo Customer",message:body.message||"",status:"open",intent:"general_support",confidence:.88,recommendation:"Route to the appropriate support queue.",escalated:false,createdAt:now()};
        write("apu.aiArchitect.tickets",[item,...tickets]); return json(item,201);
      }
      const classify=url.pathname.match(/^\/api\/tickets\/([^/]+)\/classify$/);
      if(classify && method==="POST") return json({ticketId:classify[1],intent:"technical_support",confidence:.93,recommendation:"Validate service health and assign to platform support.",escalate:false});

      if (url.pathname === "/api/predict/models" && method === "GET") return json(models);
      if (url.pathname === "/api/predict" && method === "POST") return json({prediction:body.modelType==="loan_risk"?"low_risk":body.modelType==="sales_forecast"?"growth_expected":"retention_likely",confidence:.89,explanation:[{feature:"engagement_score",importance:.38},{feature:"tenure",importance:.27},{feature:"support_activity",importance:.16}],modelVersion:"static-demo-v1",latencyMs:46});

      if (url.pathname === "/api/security" && method === "GET") return json({overallScore:94,riskLevel:"low",checklist:{dataPrivacy:93,apiSecurity:96,accessControl:92,compliance:91},roles:[{role:"Administrator",count:4,permissions:["manage","audit","deploy"]},{role:"AI Engineer",count:12,permissions:["train","evaluate","monitor"]},{role:"Viewer",count:36,permissions:["read"]}]});
      if (url.pathname === "/api/security/audit-log" && method === "GET") return json([{id:"audit-001",timestamp:"2025-05-10T08:22:00Z",user:"admin@architect.lab",action:"DEPLOY_MODEL",resource:"churn-v2.4.1",result:"success",ipAddress:"10.20.1.18"},{id:"audit-002",timestamp:"2025-05-10T07:10:00Z",user:"governance@architect.lab",action:"APPROVE_MODEL_CARD",resource:"loan-v3.1.2",result:"review_required",ipAddress:"10.20.1.24"}]);

      if (url.pathname === "/api/blueprints" && method === "GET") return json(blueprints);
      const bpMatch=url.pathname.match(/^\/api\/blueprints\/([^/]+)$/);
      if(bpMatch && method==="GET") return json(blueprints.find(x=>x.id===bpMatch[1])||blueprints[0]);

      if (url.pathname === "/api/resume-match/candidates" && method === "GET") return json(candidates);
      if (url.pathname === "/api/resume-match" && method === "POST") {
        const candidate=candidates.find(x=>x.id===body.candidateId)||candidates[0];
        return json({candidateId:candidate.id,matchScore:candidate.matchScore||88,skillGap:["Advanced FinOps"],matchedSkills:candidate.skills,explanation:"Strong alignment across architecture, cloud, delivery, and governance.",biasWarning:"Fairness checks passed: role-relevant skills only."});
      }

      if (url.pathname === "/api/extract" && method === "POST") return json({documentType:body.documentType||"report",fields:{title:"Enterprise AI Architecture Report",date:"2026-06-14",owner:"AI Architecture Office",status:"Reviewed"},confidence:.94,tags:["enterprise-ai","architecture","governance","security"]});
      if (url.pathname === "/api/summarize" && method === "POST") return json({summary:"A secure enterprise AI platform with governed retrieval, observable serving, access controls, and measurable outcomes.",keyPoints:["Centralize governance","Ground responses","Monitor quality and risk","Retain human approval"],wordCount:(body.content||"").split(/\s+/).filter(Boolean).length,readingTime:2});
      if (url.pathname === "/api/search" && method === "GET") {
        const q=url.searchParams.get("q")||"AI architecture";
        return json([{id:"sr-001",title:"AI Strategy 2025",excerpt:`Relevant section for “${q}”.`,relevanceScore:.94,type:"pdf"},{id:"sr-002",title:"Cloud Architecture Guide",excerpt:"Deployment, scaling, observability, and security.",relevanceScore:.86,type:"docx"}]);
      }

      if (url.pathname === "/api/agent-workflow/history" && method === "GET") return json(history);
      if (url.pathname === "/api/agent-workflow" && method === "POST") {
        const id=`WF-${Date.now().toString().slice(-6)}`;
        const result={workflowId:id,status:body.requireApproval?"pending_approval":"completed",steps:[{stepId:"1",name:"Plan",tool:"Planner",status:"completed",output:"Task decomposed",durationMs:420},{stepId:"2",name:"Retrieve",tool:"Knowledge Search",status:"completed",output:"Evidence collected",durationMs:680},{stepId:"3",name:"Analyze",tool:"Reasoning Engine",status:"completed",output:"Recommendations prepared",durationMs:910},{stepId:"4",name:"Review",tool:"Human Gate",status:body.requireApproval?"pending":"completed",output:body.requireApproval?"Approval required":"Approved",durationMs:190}],output:"Static workflow completed with traceable steps.",pendingApproval:!!body.requireApproval};
        write("apu.aiArchitect.workflows",[{workflowId:id,task:body.task||"Demo workflow",status:result.status,startedAt:now(),completedAt:body.requireApproval?null:now(),stepsCount:result.steps.length},...history]);
        return json(result);
      }

      if (url.pathname === "/api/roi/presets" && method === "GET") return json(presets);
      if (url.pathname === "/api/roi" && method === "POST") {
        const users=Number(body.userCount||1000),requests=Number(body.requestsPerDay||50000);
        const monthlyCloudCost=Math.round(850+users*.55+requests*.018);
        const developmentCost=Math.round(Number(body.developmentMonths||6)*Number(body.teamSize||5)*8500);
        const monthlySaving=Math.round(users*42);
        return json({monthlyCloudCost,developmentCost,monthlySaving,roiPercent:Math.round(((monthlySaving*12-developmentCost)/(developmentCost||1))*100),breakEvenMonths:Number((developmentCost/Math.max(1,monthlySaving-monthlyCloudCost)).toFixed(1)),recommendation:"Start with a governed pilot and scale after validating adoption, quality, and unit economics.",breakdown:{compute:Math.round(monthlyCloudCost*.46),storage:Math.round(monthlyCloudCost*.16),api:Math.round(monthlyCloudCost*.27),monitoring:Math.round(monthlyCloudCost*.11)}});
      }

      if (url.pathname === "/api/cloud-compare" && method === "GET") return json(cloud);
      if (url.pathname === "/api/governance" && method === "GET") return json({complianceScore:78,openRisks:risks.filter(x=>x.status==="open").length,pendingApprovals:3,lastAudit:"2025-04-30T00:00:00Z",modelCards:[{modelId:"churn-v2.4.1",name:"Churn Predictor",fairnessScore:87,biasDetected:false},{modelId:"loan-v3.1.2",name:"Loan Risk Assessment",fairnessScore:61,biasDetected:true},{modelId:"support-v1.3.0",name:"Support Classifier",fairnessScore:92,biasDetected:false}]});
      if (url.pathname === "/api/governance/risk-register" && method === "GET") return json(risks);
      if (url.pathname === "/api/governance/incident-log" && method === "GET") return json(incidents);

      if ((url.pathname === "/api/contact" || url.pathname === "/api/book-call") && method === "POST") return json({id:`CNT-${Date.now().toString(36).toUpperCase()}`,status:url.pathname.endsWith("book-call")?"queued":"received",message:url.pathname.endsWith("book-call")?"Your demo call request has been queued locally.":"Your demo inquiry has been recorded locally.",submittedAt:now()});
    }

    // Safe empty fallback for optional server-backed demonstrations.
    if (method === "GET") return json([]);
    return json({success:true,message:"Static browser-local demo response"});
  }

  window.fetch = async function(input, options) {
    const requestUrl = typeof input === "string" ? input : input.url;
    const requestPath = new URL(requestUrl, location.origin).pathname;
    const shortenerApi = appId === "url-shortener" && requestPath.startsWith("/api/links");
    const localModeKey = "apu.urlShortenerLocalMode";

    // URL Shortener prefers the real Cloudflare API so copied aliases work publicly.
    // It falls back to browser-local CRUD for local preview or an unconfigured D1 binding.
    if (shortenerApi && localStorage.getItem(localModeKey) !== "true") {
      try {
        const networkResponse = await nativeFetch(input, options);
        const responseType = (networkResponse.headers.get("content-type") || "").toLowerCase();
        if (networkResponse.ok && responseType.includes("application/json")) return networkResponse;
        if (!networkResponse.ok && networkResponse.status !== 404 && networkResponse.status < 500) return networkResponse;
        // A static Pages SPA fallback often returns index.html with HTTP 200 for /api/links.
        // Treat non-JSON responses as an unconfigured API and switch to browser-local CRUD.
        localStorage.setItem(localModeKey, "true");
      } catch (error) {
        localStorage.setItem(localModeKey, "true");
        console.info("URL Shortener is using browser-local preview mode.", error);
      }
    }

    try {
      const mocked = await mockApi(input, options);
      if (mocked) return mocked;
    } catch (error) {
      console.warn("Mock API fallback error:", error);
    }
    return nativeFetch(input, options);
  };

  // Add a compact return control only when a project is opened directly.
  if (window.top === window.self && location.pathname.startsWith("/projects/")) {
    window.addEventListener("DOMContentLoaded", () => {
      const link = document.createElement("a");
      link.href = "/";
      link.textContent = "← Project Universe";
      link.setAttribute("aria-label", "Kembali ke Project Universe");
      Object.assign(link.style, {
        position:"fixed",left:"12px",bottom:"12px",zIndex:"2147483647",
        padding:"9px 13px",border:"2px solid #111",borderRadius:"999px",
        background:"#dadada",color:"#111",font:"700 12px system-ui,sans-serif",
        textDecoration:"none",boxShadow:"4px 4px 0 #111"
      });
      document.body.appendChild(link);
    });
  }
})();
