// Force Technologies AS6171A Lab Platform — sample data store
// All sample, fictionalised.

const TODAY = new Date('2026-04-29');
const fmtDate = (d) => {
  const dt = (typeof d === 'string') ? new Date(d) : d;
  return dt.toISOString().slice(0,10);
};
const fmtDateTime = (d) => {
  const dt = (typeof d === 'string') ? new Date(d) : d;
  return dt.toISOString().slice(0,16).replace('T',' ');
};
const daysAgo = (n) => { const d = new Date(TODAY); d.setDate(d.getDate() - n); return d; };

// =============================================================================
// TEST GROUPS & TESTS DICTIONARY (admin-configurable, per Paul's revised spec)
// =============================================================================
// Each Group has: name, number (3-digit, e.g. "1.0.0"), category, as6171Id
// Each Test belongs to a Group, has: title, number (extension e.g. "1.1.0")
const TEST_GROUPS = [
  {
    id: 'g-ev', number: '1.0.0', name: 'External Visual Inspection',
    category: 'Non-destructive', as6171Id: 'AS6171A (Moderate Risk) Model 2',
    tests: [
      { id: 't-evcdm', number: '1.1.0', title: 'Counterfeit Detection Marking (remarking, blacktopping)' },
      { id: 't-evdr',  number: '1.2.0', title: 'Dimensional verification' },
      { id: 't-evrt',  number: '1.3.0', title: 'Lead / terminal re-tinning inspection' },
    ],
  },
  {
    id: 'g-xrf', number: '2.0.0', name: 'X-Ray Fluorescence (XRF)',
    category: 'Non-destructive', as6171Id: 'AS6171A (Moderate Risk) Model 2',
    tests: [
      { id: 't-xrfbody', number: '2.1.0', title: 'Body / mould compound composition' },
      { id: 't-xrflead', number: '2.2.0', title: 'Lead / termination finish composition' },
    ],
  },
  {
    id: 'g-res', number: '3.0.0', name: 'Resistance to Solvents',
    category: 'Non-destructive', as6171Id: 'AS6171A (Moderate Risk) Model 2',
    tests: [
      { id: 't-res1', number: '3.1.0', title: 'Reagent 1 — Mineral spirits / alcohol mix (70/30)' },
      { id: 't-res2', number: '3.2.0', title: 'Reagent 2 — Ethyl acetate' },
      { id: 't-res3', number: '3.3.0', title: 'Reagent 3 — De-Ionised water' },
    ],
  },
  {
    id: 'g-xray', number: '4.0.0', name: 'Radiological (X-Ray) Inspection',
    category: 'Non-destructive', as6171Id: 'AS6171A (Moderate Risk) Model 2',
    tests: [
      { id: 't-xrint', number: '4.1.0', title: 'Internal die geometry verification' },
      { id: 't-xrbond', number: '4.2.0', title: 'Bond wire imaging' },
      { id: 't-xrlf',   number: '4.3.0', title: 'Lead frame inspection' },
    ],
  },
  {
    id: 'g-csam', number: '5.0.0', name: 'Acoustic Microscopy (CSAM)',
    category: 'Non-destructive', as6171Id: 'AS6171A (Moderate Risk) Model 2',
    tests: [
      { id: 't-csam1', number: '5.1.0', title: 'Die attach delamination' },
      { id: 't-csam2', number: '5.2.0', title: 'Mould compound void analysis' },
    ],
  },
  {
    id: 'g-decap', number: '6.0.0', name: 'Decapsulation & Internal Visual',
    category: 'Destructive', as6171Id: 'AS6171A (Moderate Risk) Model 2',
    tests: [
      { id: 't-dec1', number: '6.1.0', title: 'Chemical decapsulation' },
      { id: 't-dec2', number: '6.2.0', title: 'Die surface inspection' },
      { id: 't-dec3', number: '6.3.0', title: 'Die markings verification' },
    ],
  },
  {
    id: 'g-et', number: '7.0.0', name: 'Electrical Test (DC Parametric)',
    category: 'Non-destructive', as6171Id: 'AS6171A (Moderate Risk) Model 2',
    tests: [
      { id: 't-et1', number: '7.1.0', title: 'Supply current verification' },
      { id: 't-et2', number: '7.2.0', title: 'Threshold / offset parameters' },
    ],
  },
];

const OUTCOMES = ['Acceptable','Suspect','Not Accepted','Not Available'];

// =============================================================================
// USERS — now with initials + signature (per Paul's spec)
// =============================================================================
const USERS = [
  { id: 'u1', name: 'Marcus Webb',     initials: 'MWB', email: 'm.webb@forcetechnologies.co.uk',
    role: 'Test Engineer', active: true, lastLogin: '2026-04-29 08:14',
    signature: 'Marcus Webb' },
  { id: 'u2', name: 'Priya Anand',     initials: 'PRA', email: 'p.anand@forcetechnologies.co.uk',
    role: 'Test Engineer', active: true, lastLogin: '2026-04-29 09:02',
    signature: 'P. Anand' },
  { id: 'u3', name: 'David Okonkwo',   initials: 'DPO', email: 'd.okonkwo@forcetechnologies.co.uk',
    role: 'Approver', active: true, lastLogin: '2026-04-29 07:48',
    signature: 'D. Okonkwo' },
  { id: 'u4', name: 'Helen Ridgeway',  initials: 'HCR', email: 'h.ridgeway@forcetechnologies.co.uk',
    role: 'Approver', active: true, lastLogin: '2026-04-28 16:22',
    signature: 'H. Ridgeway' },
  { id: 'u5', name: 'Tom Castellan',   initials: 'TJC', email: 't.castellan@forcetechnologies.co.uk',
    role: 'Admin', active: true, lastLogin: '2026-04-29 06:55',
    signature: 'T. Castellan' },
  { id: 'u6', name: 'Sarah Bramwell',  initials: 'SBW', email: 's.bramwell@forcetechnologies.co.uk',
    role: 'Test Engineer', active: true, lastLogin: '2026-04-28 17:30',
    signature: 'S. Bramwell' },
  { id: 'u7', name: 'Rajesh Iyer',     initials: 'RIY', email: 'r.iyer@forcetechnologies.co.uk',
    role: 'Test Engineer', active: false, lastLogin: '2026-03-12 11:04',
    signature: 'R. Iyer' },
];

// Customers
const CUSTOMERS = [
  { id: 'c1', name: 'Lockharte Aerospace Ltd',   contact: 'Andrea Holst',     email: 'a.holst@lockharte.com',     phone: '+44 1234 567890',
    address: 'Lockharte House, 14 Aldermoor Way, Bristol BS34 8YE, United Kingdom' },
  { id: 'c2', name: 'Northwind Defense Systems', contact: 'James Rallston',   email: 'j.rallston@northwind-ds.com', phone: '+44 207 555 0142',
    address: 'Northwind House, 80 Kings Road, Reading RG1 4HG, United Kingdom' },
  { id: 'c3', name: 'Meridian Avionics Group',   contact: 'Catherine Yu',     email: 'c.yu@meridian-avionics.com', phone: '+44 1483 224 119',
    address: 'Building 4, Aerospace Park, Farnborough GU14 6XT, United Kingdom' },
  { id: 'c4', name: 'Halberd Marine Electronics',contact: 'Owen MacIntyre',   email: 'o.macintyre@halberd-me.com', phone: '+44 1752 991 220',
    address: '12 Quayside Drive, Plymouth PL1 3RP, United Kingdom' },
  { id: 'c5', name: 'Solaris Space Components',  contact: 'Dr. Mira Köhler',  email: 'm.kohler@solaris-sc.com',    phone: '+49 89 4520 9920',
    address: 'Brunhamstrasse 4, 81249 München, Germany' },
];

// =============================================================================
// EQUIPMENT — now with lastCalibrated (per Paul's spec)
// =============================================================================
const EQUIPMENT = [
  { id: 'eq1', name: 'Leica M205 A Stereo Microscope', tag: 'FT-MIC-014', category: 'Microscopy',
    serial: 'M205-114882', manufacturer: 'Leica Microsystems', model: 'M205 A',
    location: 'Bay 3', lastCalibrated: '2025-08-12', calibrationDue: '2026-08-12', status: 'In Service' },
  { id: 'eq2', name: 'Hitachi SEM-IT500', tag: 'FT-SEM-002', category: 'Microscopy',
    serial: 'IT500-22094', manufacturer: 'Hitachi', model: 'SU3900',
    location: 'Bay 6 (Cleanroom)', lastCalibrated: '2025-12-04', calibrationDue: '2026-06-04', status: 'In Service' },
  { id: 'eq3', name: 'Bruker S2 Puma XRF', tag: 'FT-XRF-001', category: 'Spectroscopy',
    serial: 'S2P-44102', manufacturer: 'Bruker', model: 'S2 Puma',
    location: 'Bay 4', lastCalibrated: '2025-07-18', calibrationDue: '2026-07-18', status: 'In Service' },
  { id: 'eq4', name: 'Nikon XT H 225 ST X-Ray', tag: 'FT-XRY-001', category: 'Radiography',
    serial: 'XTH225-07731', manufacturer: 'Nikon Metrology', model: 'XT H 225 ST',
    location: 'Bay 7 (Shielded)', lastCalibrated: '2025-09-22', calibrationDue: '2026-09-22', status: 'In Service' },
  { id: 'eq5', name: 'Sonoscan D9600 C-SAM', tag: 'FT-CSAM-001', category: 'Acoustic',
    serial: 'D9600-3142', manufacturer: 'Sonoscan', model: 'D9600',
    location: 'Bay 5', lastCalibrated: '2025-11-30', calibrationDue: '2026-05-30', status: 'In Service' },
  { id: 'eq6', name: 'Nisene JetEtch Pro Decap', tag: 'FT-DEC-001', category: 'Sample Prep',
    serial: 'JEP-20214', manufacturer: 'Nisene Technology', model: 'JetEtch Pro',
    location: 'Wet Lab', lastCalibrated: '2025-10-04', calibrationDue: '2026-10-04', status: 'In Service' },
  { id: 'eq7', name: 'Keysight B2902B SMU', tag: 'FT-SMU-005', category: 'Electrical',
    serial: 'B2902B-91720', manufacturer: 'Keysight', model: 'B2902B',
    location: 'Bay 2', lastCalibrated: '2025-10-30', calibrationDue: '2026-04-30', status: 'In Service' },
  { id: 'eq8', name: 'Mitutoyo Digital Caliper', tag: 'FT-CAL-022', category: 'Dimensional',
    serial: 'CD-6CSX-228', manufacturer: 'Mitutoyo', model: 'CD-6"CSX',
    location: 'Bay 3', lastCalibrated: '2025-08-14', calibrationDue: '2026-02-14', status: 'Out of Service' },
];

// Standard responses (searchable dropdown source)
const STANDARD_RESPONSES = [
  { id: 'sr1', category: 'External Visual', title: 'No counterfeit indicators observed',
    body: 'External visual inspection conducted at 7×–40× magnification under coaxial and ring illumination. No evidence of remarking, blacktopping, sanding, resurfacing, scratching, fingerprinting, mould reflow, or laser overburn was observed across the inspected sample.' },
  { id: 'sr2', category: 'External Visual', title: 'Minor handling marks within tolerance',
    body: 'Surface inspection identified minor handling marks consistent with normal storage and shipment. No counterfeit indicators per AS6171A §4.2 were observed.' },
  { id: 'sr3', category: 'XRF', title: 'Lead-free composition consistent with declared part',
    body: 'XRF analysis of body, lead, and termination materials returned compositions consistent with the declared lead-free finish. Sn matrix > 95 wt%; trace constituents within expected ranges per the manufacturer datasheet.' },
  { id: 'sr4', category: 'Solvents', title: 'Marking permanency satisfactory',
    body: 'Markings remained legible and contiguous following 30-second exposure to each of the three reagents specified in the test plan, with cotton-tipped applicator wipe-through. No transfer of marking ink was observed.' },
  { id: 'sr5', category: 'Acoustic', title: 'No delamination detected',
    body: 'C-mode scanning acoustic microscopy of die attach and mould compound interfaces returned no indications of delamination, voids, or cracks above the 5% area threshold defined by the test plan.' },
  { id: 'sr6', category: 'Decapsulation', title: 'Die markings consistent with reference',
    body: 'Decapsulated die exhibits manufacturer logo, mask set ID, and date code consistent with authorised references. No evidence of die substitution observed.' },
  { id: 'sr7', category: 'Cover Page', title: 'Standard limitation of liability',
    body: 'This report is issued on the basis of the test plan agreed with the customer at the date of acceptance. Findings apply only to the samples received and tested. Force Technologies accepts no liability for inferences drawn beyond the tested population.' },
  { id: 'sr8', category: 'Cover Page', title: 'Standard chain-of-custody statement',
    body: 'Samples were received in sealed packaging on the date stated and stored under controlled conditions consistent with manufacturer recommendations until tested. Chain of custody is logged in the laboratory information system.' },
];

// =============================================================================
// TEST PLAN TEMPLATES (admin-managed; pre-select groups+tests in wizard)
// =============================================================================
const TEST_PLAN_TEMPLATES = [
  { id: 'tpl-mr-m2-full', name: 'AS6171A Moderate Risk · Model 2 — Full',
    groupIds: ['g-ev','g-xrf','g-res','g-xray','g-csam','g-decap','g-et'], testIds: 'all' },
  { id: 'tpl-mr-m2-nde',  name: 'AS6171A Moderate Risk · Model 2 — Non-destructive only',
    groupIds: ['g-ev','g-xrf','g-res','g-xray','g-csam','g-et'], testIds: 'all' },
  { id: 'tpl-screen',     name: 'Visual + XRF screening (fast-turn)',
    groupIds: ['g-ev','g-xrf'], testIds: 'all' },
];

// =============================================================================
// JOBS — now carry: device list, group results (with per-test device tag lists)
// =============================================================================
function makeDevices(n) { return Array.from({ length: n }, (_, i) => `D-${String(i+1).padStart(2,'0')}`); }

// build group results for a job: each group has tests with outcome buckets + per-test comments
function buildGroupResults(devices, status) {
  return TEST_GROUPS.map((g, gIdx) => {
    const groupComplete = status === 'complete' || (status === 'partial' && gIdx < 3);
    const groupInProg = status === 'partial' && gIdx === 3;
    return {
      groupId: g.id,
      status: groupComplete ? 'Complete' : groupInProg ? 'In Progress' : 'Planned',
      groupOutcome: groupComplete ? (gIdx === 3 ? 'Passed' : 'Passed') : null,
      devicesTested: groupComplete ? devices.slice() : (groupInProg ? devices.slice(0, Math.min(5, devices.length)) : []),
      observationsSummary: groupComplete ? `All devices passed ${g.name.toLowerCase()} against AS6171A acceptance criteria.` : '',
      testerId: groupComplete ? (gIdx % 2 === 0 ? 'u1' : 'u2') : null,
      tests: g.tests.map((t, tIdx) => ({
        testId: t.id,
        acceptable: groupComplete ? devices.slice() : (groupInProg && tIdx === 0 ? devices.slice(0, 3) : []),
        suspect: [],
        notAccepted: [],
        notAvailable: [],
        comments: groupComplete ? `${t.title} performed per procedure. No anomalies observed.` : '',
      })),
      evidence: groupComplete ? Array.from({ length: 4 }, (_, i) => ({
        id: `${g.id}-f${i+1}`, label: `${g.number.slice(0,1)}.${i+1}`,
        caption: ['Setup', 'Sample tray', 'Reference image', 'Result overview'][i],
        size: i === 0 ? 'full' : 'half', sort: i,
      })) : [],
    };
  });
}

// special case: j1 has group 3 (RES) in progress with a Suspect device
function makeFocusJobGroupResults(devices) {
  return TEST_GROUPS.map((g, gIdx) => {
    if (gIdx < 2) {
      // groups 1 & 2 complete
      return {
        groupId: g.id, status: 'Complete', groupOutcome: 'Passed',
        devicesTested: devices.slice(),
        observationsSummary: gIdx === 0
          ? 'All 10 devices passed external visual inspection. No counterfeit indicators observed.'
          : 'XRF compositions consistent with declared part for all 10 devices.',
        testerId: 'u1',
        tests: g.tests.map((t) => ({
          testId: t.id,
          acceptable: devices.slice(), suspect: [], notAccepted: [], notAvailable: [],
          comments: 'No anomalies observed.',
        })),
        evidence: Array.from({ length: 4 }, (_, i) => ({
          id: `${g.id}-f${i+1}`, label: `${g.number.slice(0,1)}.${i+1}`,
          caption: ['Setup overview','Sample tray (D-01 → D-10)','Reference image','Result composite'][i],
          size: i === 0 ? 'full' : i === 3 ? 'half' : 'third', sort: i,
        })),
      };
    }
    if (gIdx === 2) {
      // group 3 RES in progress; sample D-07 suspect
      return {
        groupId: g.id, status: 'In Progress', groupOutcome: null,
        devicesTested: devices.slice(),
        observationsSummary: 'Markings remained legible across 9 of 10 specimens. Device D-07 showed partial transfer of marking ink under reagent 2 (ethyl acetate) on the second wipe — see evidence figures.',
        testerId: 'u1',
        tests: g.tests.map((t, tIdx) => ({
          testId: t.id,
          acceptable: tIdx === 1 ? devices.filter((d) => d !== 'D-07') : devices.slice(),
          suspect: tIdx === 1 ? ['D-07'] : [],
          notAccepted: [],
          notAvailable: [],
          comments: tIdx === 1
            ? 'D-07 showed marking transfer on second wipe — flagged for cross-reference at decapsulation.'
            : 'All devices passed; markings remained legible following reagent exposure.',
        })),
        evidence: [
          { id: 'g-res-f1', label: '3.1', caption: 'Reagent station — pre-test', size: 'full', sort: 0 },
          { id: 'g-res-f2', label: '3.2', caption: 'Sample tray (D-01 → D-10)', size: 'half', sort: 1 },
          { id: 'g-res-f3', label: '3.3', caption: 'D-07 marking transfer (post-reagent 2)', size: 'half', sort: 2 },
          { id: 'g-res-f4', label: '3.4', caption: 'D-07 close-up @ 40×', size: 'third', sort: 3 },
          { id: 'g-res-f5', label: '3.5', caption: 'D-04 reference (post-test, no transfer)', size: 'third', sort: 4 },
          { id: 'g-res-f6', label: '3.6', caption: 'Reagent application apparatus', size: 'third', sort: 5 },
        ],
      };
    }
    return {
      groupId: g.id, status: 'Planned', groupOutcome: null,
      devicesTested: [], observationsSummary: '', testerId: null,
      tests: g.tests.map((t) => ({
        testId: t.id, acceptable: [], suspect: [], notAccepted: [], notAvailable: [], comments: '',
      })),
      evidence: [],
    };
  });
}

const JOBS = [
  {
    id: 'j1',
    reportNumber: 'FT-CR-2026-0184',
    customerJobRef: 'LKH-PO-22094-A',
    title: 'AS6171A Counterfeit Risk Mitigation — TI LM393DR',
    customerId: 'c1',
    partNumber: 'LM393DR', partDescription: 'Dual Differential Comparator, SOIC-8',
    manufacturer: 'Texas Instruments',
    dateCode: '2417', lotCode: 'TI-2417-A88',
    quantityReceived: 50, sampleQty: 10,
    devices: makeDevices(10),
    receivedDate: '2026-04-22', targetIssueDate: '2026-05-08',
    status: 'In Progress',
    engineerIds: ['u1','u2'], approverIds: ['u3','u4'],
    templateId: 'tpl-mr-m2-full',
    groupIds: ['g-ev','g-xrf','g-res','g-xray','g-csam','g-decap','g-et'],
    createdAt: '2026-04-22 09:14',
    submittedForApprovalAt: null, approvedAt: null, issuedAt: null,
    groupResults: makeFocusJobGroupResults(makeDevices(10)),
  },
  {
    id: 'j2',
    reportNumber: 'FT-CR-2026-0181',
    customerJobRef: 'NWD-22-7714',
    title: 'AS6171A Counterfeit Risk Mitigation — AD AD8232ACPZ',
    customerId: 'c2',
    partNumber: 'AD8232ACPZ', partDescription: 'Single-Lead Heart Rate Monitor Front-End, LFCSP-20',
    manufacturer: 'Analog Devices',
    dateCode: '2348', lotCode: 'AD-2348-002',
    quantityReceived: 30, sampleQty: 10,
    devices: makeDevices(10),
    receivedDate: '2026-04-15', targetIssueDate: '2026-04-30',
    status: 'For Approval',
    engineerIds: ['u2'], approverIds: ['u3'],
    templateId: 'tpl-mr-m2-full',
    groupIds: ['g-ev','g-xrf','g-res','g-xray','g-csam','g-decap','g-et'],
    createdAt: '2026-04-15 10:08',
    submittedForApprovalAt: '2026-04-28 16:42', approvedAt: null, issuedAt: null,
    groupResults: buildGroupResults(makeDevices(10), 'complete'),
  },
  {
    id: 'j3',
    reportNumber: 'FT-CR-2026-0179',
    customerJobRef: 'MAG-Q1-0042',
    title: 'AS6171A Counterfeit Risk Mitigation — Microchip ATSAMD21G18A-AU',
    customerId: 'c3',
    partNumber: 'ATSAMD21G18A-AU', partDescription: '32-bit ARM Cortex-M0+ Microcontroller, TQFP-48',
    manufacturer: 'Microchip',
    dateCode: '2402', lotCode: 'MCP-2402-X3',
    quantityReceived: 25, sampleQty: 10,
    devices: makeDevices(10),
    receivedDate: '2026-04-10', targetIssueDate: '2026-04-29',
    status: 'Rejected',
    engineerIds: ['u6'], approverIds: ['u4'],
    templateId: 'tpl-mr-m2-full',
    groupIds: ['g-ev','g-xrf','g-res','g-xray','g-csam','g-decap','g-et'],
    createdAt: '2026-04-10 11:30',
    submittedForApprovalAt: '2026-04-26 14:18',
    rejectedAt: '2026-04-27 08:20',
    rejectionReason: 'X-Ray inspection (Group 4) commentary references the wrong reference image. Please re-state observations against Figure 4.2 and re-submit. Also confirm aperture setting on equipment record.',
    rejectedById: 'u4',
    approvedAt: null, issuedAt: null,
    groupResults: buildGroupResults(makeDevices(10), 'complete'),
  },
  {
    id: 'j4',
    reportNumber: 'FT-CR-2026-0177',
    customerJobRef: 'HME-2026-117',
    title: 'AS6171A Counterfeit Risk Mitigation — STMicro STM32F407VGT6',
    customerId: 'c4',
    partNumber: 'STM32F407VGT6', partDescription: 'High-performance ARM Cortex-M4, LQFP-100',
    manufacturer: 'STMicroelectronics',
    dateCode: '2331', lotCode: 'ST-2331-K9',
    quantityReceived: 40, sampleQty: 10,
    devices: makeDevices(10),
    receivedDate: '2026-04-08', targetIssueDate: '2026-04-28',
    status: 'Approved',
    engineerIds: ['u1'], approverIds: ['u3'],
    templateId: 'tpl-mr-m2-full',
    groupIds: ['g-ev','g-xrf','g-res','g-xray','g-csam','g-decap','g-et'],
    createdAt: '2026-04-08 09:00',
    submittedForApprovalAt: '2026-04-25 17:14',
    approvedAt: '2026-04-26 10:08', issuedAt: null,
    groupResults: buildGroupResults(makeDevices(10), 'complete'),
  },
  {
    id: 'j5',
    reportNumber: 'FT-CR-2026-0172',
    customerJobRef: 'SSC-CO-2026-08',
    title: 'AS6171A Counterfeit Risk Mitigation — Xilinx XC7A35T-2FGG484I',
    customerId: 'c5',
    partNumber: 'XC7A35T-2FGG484I', partDescription: 'Artix-7 FPGA, 484-FBGA',
    manufacturer: 'Xilinx (AMD)',
    dateCode: '2245', lotCode: 'XLX-2245-V2',
    quantityReceived: 12, sampleQty: 8,
    devices: makeDevices(8),
    receivedDate: '2026-03-28', targetIssueDate: '2026-04-18',
    status: 'Complete',
    engineerIds: ['u2'], approverIds: ['u3'],
    templateId: 'tpl-mr-m2-full',
    groupIds: ['g-ev','g-xrf','g-res','g-xray','g-csam','g-decap','g-et'],
    createdAt: '2026-03-28 14:11',
    submittedForApprovalAt: '2026-04-15 12:22',
    approvedAt: '2026-04-16 09:33', issuedAt: '2026-04-16 10:01',
    groupResults: buildGroupResults(makeDevices(8), 'complete'),
  },
  {
    id: 'j6',
    reportNumber: 'FT-CR-2026-0186',
    customerJobRef: 'LKH-PO-22142-B',
    title: 'AS6171A Counterfeit Risk Mitigation — NXP MCIMX6Q5EYM10AC',
    customerId: 'c1',
    partNumber: 'MCIMX6Q5EYM10AC', partDescription: 'i.MX 6Quad Applications Processor, FCPBGA-624',
    manufacturer: 'NXP',
    dateCode: '2418', lotCode: 'NXP-2418-Q1',
    quantityReceived: 6, sampleQty: 4,
    devices: makeDevices(4),
    receivedDate: '2026-04-28', targetIssueDate: '2026-05-15',
    status: 'Planned',
    engineerIds: ['u6'], approverIds: ['u4'],
    templateId: 'tpl-mr-m2-nde',
    groupIds: ['g-ev','g-xrf','g-res','g-xray','g-csam','g-et'],
    createdAt: '2026-04-28 16:01',
    submittedForApprovalAt: null, approvedAt: null, issuedAt: null,
    groupResults: buildGroupResults(makeDevices(4), 'planned'),
  },
];

// =============================================================================
// PER-JOB AUDIT (replaces global audit — Paul: audit log is per-job)
// =============================================================================
const JOB_AUDIT = {
  j1: [
    { when: '2026-04-29 09:42', userId: 'u1', what: 'Saved Group 3 — Resistance to Solvents (draft)', detail: 'D-07 flagged Suspect on Reagent 2.' },
    { when: '2026-04-29 08:42', userId: 'u1', what: 'Started Group 3 — Resistance to Solvents' },
    { when: '2026-04-28 17:10', userId: 'u1', what: 'Completed Group 2 — XRF', detail: 'Outcome: Passed; 10/10 devices.' },
    { when: '2026-04-27 11:30', userId: 'u1', what: 'Completed Group 1 — External Visual Inspection', detail: 'Outcome: Passed; 10/10 devices.' },
    { when: '2026-04-23 09:30', userId: 'u1', what: 'Devices registered', detail: '10 devices added (D-01 → D-10).' },
    { when: '2026-04-22 09:14', userId: 'u1', what: 'Job created', detail: 'Template: AS6171A MR · M2 — Full.' },
  ],
  j2: [
    { when: '2026-04-28 16:42', userId: 'u2', what: 'Submitted for approval', detail: 'To D. Okonkwo.' },
    { when: '2026-04-28 15:30', userId: 'u2', what: 'Completed Group 7 — Electrical Test' },
    { when: '2026-04-27 10:14', userId: 'u2', what: 'Completed Group 4 — X-Ray Inspection' },
    { when: '2026-04-15 10:08', userId: 'u2', what: 'Job created' },
  ],
  j3: [
    { when: '2026-04-27 08:20', userId: 'u4', what: 'Rejected — see comment', detail: 'X-Ray group commentary references wrong reference image.' },
    { when: '2026-04-26 14:18', userId: 'u6', what: 'Submitted for approval' },
    { when: '2026-04-10 11:30', userId: 'u6', what: 'Job created' },
  ],
  j4: [
    { when: '2026-04-26 10:08', userId: 'u3', what: 'Approved', detail: 'All groups passed.' },
    { when: '2026-04-25 17:14', userId: 'u1', what: 'Submitted for approval' },
    { when: '2026-04-08 09:00', userId: 'u1', what: 'Job created' },
  ],
  j5: [
    { when: '2026-04-16 10:01', userId: 'u3', what: 'Issued — PDF released to customer' },
    { when: '2026-04-16 09:33', userId: 'u3', what: 'Approved' },
    { when: '2026-04-15 12:22', userId: 'u2', what: 'Submitted for approval' },
    { when: '2026-03-28 14:11', userId: 'u2', what: 'Job created' },
  ],
  j6: [
    { when: '2026-04-28 16:01', userId: 'u6', what: 'Job created' },
  ],
};

// Comments per job — top level (Job > Comments tab)
const JOB_COMMENTS = {
  j1: [
    { id: 'jc1', when: '2026-04-29 09:45', userId: 'u1',
      body: 'Reagent 2 result on D-07 looks like a Suspect to me — flagging for decapsulation cross-check at Group 6.' },
    { id: 'jc2', when: '2026-04-29 09:50', userId: 'u3',
      body: 'Agreed. Make sure the cover page summary calls this out before submitting for approval.' },
  ],
  j2: [
    { id: 'jc3', when: '2026-04-28 16:45', userId: 'u2',
      body: 'All groups complete and reviewed internally. Ready for approval.' },
  ],
  j3: [
    { id: 'jc4', when: '2026-04-27 08:25', userId: 'u4',
      body: 'See rejection note — please correct reference image and resubmit.' },
  ],
  j4: [], j5: [], j6: [],
};

// Notifications for current user
const NOTIFICATIONS = [
  { id: 'n1', when: '2026-04-27 08:21', kind: 'rejection',
    title: 'FT-CR-2026-0179 returned for revision',
    body: 'H. Ridgeway has rejected this report — please review feedback and resubmit.', jobId: 'j3' },
  { id: 'n2', when: '2026-04-26 10:09', kind: 'approval',
    title: 'FT-CR-2026-0177 approved',
    body: 'D. Okonkwo has approved the report. Awaiting issue.', jobId: 'j4' },
];

// Lab info (used in PDF footer / cover)
const LAB = {
  name: 'Force Technologies Ltd — Components Laboratory',
  address: 'Force House, Bilton Way, Luton LU1 1UU, United Kingdom',
  phone: '+44 (0) 1582 723746',
  email: 'lab@forcetechnologies.co.uk',
  web: 'forcetechnologies.co.uk',
  disclaimer: 'This report is issued by Force Technologies Ltd and applies only to the items tested. The contents must not be reproduced except in full without prior written approval. Findings apply only to the samples received; no inference is made as to the wider population. Force Technologies accepts no liability for inferences drawn beyond the tested sample. Force Technologies Ltd. is registered in England (No. 02144298) at the above address.',
};

window.FORCE_DATA = {
  USERS, CUSTOMERS, EQUIPMENT, STANDARD_RESPONSES,
  JOBS, TEST_GROUPS, TEST_PLAN_TEMPLATES, OUTCOMES,
  JOB_AUDIT, JOB_COMMENTS, NOTIFICATIONS, LAB,
  fmtDate, fmtDateTime, daysAgo,
};
