// ===== Feinplanung — Stammdaten & Beispieldaten (CNC-Drehzentrum / Metallbearbeitung) =====

const SHIFT_HOURS = 8;

// Werkstoffe mit Werkstoffgruppe (für Rüstlogik)
const MATERIALS = {
  ST42: { id: 'ST42', name: 'Stahl 42CrMo4', group: 'Stahl',     color: '#8d8b86' },
  C45:  { id: 'C45',  name: 'Stahl C45',     group: 'Stahl',     color: '#9c9a94' },
  AL70: { id: 'AL70', name: 'Alu 7075',      group: 'Aluminium', color: '#9fb0bd' },
  AL60: { id: 'AL60', name: 'Alu 6082',      group: 'Aluminium', color: '#aebcc7' },
  V2A:  { id: 'V2A',  name: 'Edelstahl 1.4301', group: 'Edelstahl', color: '#8fa39a' },
  MS58: { id: 'MS58', name: 'Messing CuZn39Pb3', group: 'Messing', color: '#c2a878' },
  TI5:  { id: 'TI5',  name: 'Titan Grade 5', group: 'Titan',     color: '#b29bb0' },
};

// Rüstaufwand (Minuten) abhängig vom Werkstoffgruppen-Wechsel — Basislogik (Default-Werte)
function baseSetupMinutes(prevMatId, matId) {
  if (!prevMatId) return 25; // Erstrüsten
  const a = MATERIALS[prevMatId], b = MATERIALS[matId];
  if (a.id === b.id) return 8;            // identischer Werkstoff: nur Werkzeugkontrolle
  if (a.group === b.group) return 22;     // gleiche Gruppe
  // Gruppenwechsel: Grundreinigung + Werkzeugwechsel
  const heavy = (a.group === 'Titan' || b.group === 'Titan' || a.group === 'Edelstahl' || b.group === 'Edelstahl');
  return heavy ? 55 : 40;
}

// Effektiver Rüstaufwand: nutzt die im Admin gepflegte Rüstzeitmatrix, sonst Basislogik
function setupMinutes(prevMatId, matId) {
  const M = window.__setupMatrix;
  if (!prevMatId) return (M && M.erst != null) ? M.erst : 25;
  if (M && M[prevMatId] && M[prevMatId][matId] != null) return M[prevMatId][matId];
  return baseSetupMinutes(prevMatId, matId);
}

const WORK_SYSTEMS = [
  { id: 'WS-SG-01', name: 'Säge AS-1',                short: 'AS-1',  kap: '2-Schicht · 8 h', step: 'saegen',    goal: { durchlauf: 75, ruesten: 30, termin: 40 } },
  { id: 'WS-DZ-04', name: 'Drehzentrum DMG CTX 4',    short: 'CTX 4', kap: '3-Schicht · 8 h', step: 'drehen',    goal: { durchlauf: 35, ruesten: 75, termin: 50 } },
  { id: 'WS-DZ-02', name: 'Drehzentrum Index G220',   short: 'G220',  kap: '3-Schicht · 8 h', step: 'drehen',    goal: { durchlauf: 45, ruesten: 60, termin: 55 } },
  { id: 'WS-FR-11', name: 'Fräszentrum Hermle C42',   short: 'C42',   kap: '2-Schicht · 8 h', step: 'fraesen',   goal: { durchlauf: 40, ruesten: 55, termin: 65 } },
  { id: 'WS-EN-01', name: 'Entgratzelle EC-3',        short: 'EC-3',  kap: '1-Schicht · 8 h', step: 'entgraten', goal: { durchlauf: 80, ruesten: 20, termin: 45 } },
  { id: 'WS-MR-01', name: 'Messraum QS',              short: 'QS',    kap: '2-Schicht · 8 h', step: 'pruefen',   goal: { durchlauf: 50, ruesten: 25, termin: 80 } },
];
// Welches Arbeitssystem führt den Drehvorgang aus (zwei Drehzentren teilen sich die Last)
const DREH_WS = (i) => (i % 3 === 0 ? 'WS-DZ-02' : 'WS-DZ-04');

// 3-Schicht-Modell, 5 Tage
const SHIFT_NAMES = ['Früh', 'Spät', 'Nacht'];
const DAYS = ['Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa', 'So'];
function buildShifts(n) {
  const out = [];
  for (let i = 0; i < n; i++) {
    out.push({
      idx: i,
      name: SHIFT_NAMES[i % 3],
      day: DAYS[Math.floor(i / 3) % DAYS.length],
      startH: i * SHIFT_HOURS,
    });
  }
  return out;
}
const SHIFTS = buildShifts(24);

// Kundensegmente
const CUSTOMERS = {
  'Vossberg Antriebstechnik': 'A',
  'Nordmann Aerospace':       'A',
  'Hellwig Hydraulik':        'B',
  'Kästner Maschinenbau':     'B',
  'Pröll Feinwerktechnik':    'C',
  'Barchitec Komponenten':    'C',
};

// helper: Stunden ab "jetzt" für Plan-Termine
const H = (shiftOffset) => shiftOffset * SHIFT_HOURS;

// Fertigungsaufträge.  bestand: 'direkt' | 'indirekt' | 'route'
// frozen: bereits freigegeben & eingeplant (Teil der Frozen Zone)
const ORDERS = [
  // --- bereits freigegebene / eingeplante Aufträge (füllen die nahen Schichten) ---
  { nr: 'FA-10391', avo: '0030', kunde: 'Vossberg Antriebstechnik', mat: 'ST42', menge: 120, kurz: 'Antriebswelle AW-220', wert: 18400, dauerH: 3.5, restH: 3.5, planStart: H(-1), planEnde: H(2), bestand: 'direkt', released: true },
  { nr: 'FA-10402', avo: '0020', kunde: 'Vossberg Antriebstechnik', mat: 'ST42', menge: 90,  kurz: 'Lagerbock LB-14',     wert: 12100, dauerH: 3.0, restH: 3.0, planStart: H(0),  planEnde: H(3), bestand: 'direkt', released: true },
  { nr: 'FA-10377', avo: '0040', kunde: 'Hellwig Hydraulik',        mat: 'C45',  menge: 60,  kurz: 'Kolbenstange KS-08',   wert: 9600,  dauerH: 4.0, restH: 4.0, planStart: H(0),  planEnde: H(4), bestand: 'direkt', released: true },
  { nr: 'FA-10410', avo: '0030', kunde: 'Nordmann Aerospace',       mat: 'AL70', menge: 40,  kurz: 'Strukturhalter SH-3',  wert: 22800, dauerH: 4.5, restH: 4.5, planStart: H(1),  planEnde: H(5), bestand: 'direkt', released: true },
  { nr: 'FA-10415', avo: '0020', kunde: 'Kästner Maschinenbau',     mat: 'AL60', menge: 75,  kurz: 'Adapterflansch AF-5',  wert: 7400,  dauerH: 3.5, restH: 3.5, planStart: H(2),  planEnde: H(6), bestand: 'direkt', released: true },

  { nr: 'FA-10483', avo: '0030', kunde: 'Hellwig Hydraulik',        mat: 'C45',  menge: 70,  kurz: 'Kolbenstange KS-10',   wert: 9900,  dauerH: 4.0, restH: 4.0, planStart: H(2),  planEnde: H(6), bestand: 'direkt', released: true },
  { nr: 'FA-10488', avo: '0030', kunde: 'Hellwig Hydraulik',        mat: 'C45',  menge: 55,  kurz: 'Kolbenstange KS-11',   wert: 9200,  dauerH: 3.5, restH: 3.5, planStart: H(3),  planEnde: H(7), bestand: 'direkt', released: true },
  { nr: 'FA-10491', avo: '0020', kunde: 'Barchitec Komponenten',    mat: 'V2A',  menge: 130, kurz: 'Gehäuseflansch GF-8',  wert: 9100,  dauerH: 3.5, restH: 3.5, planStart: H(3),  planEnde: H(8), bestand: 'direkt', released: true },
  { nr: 'FA-10495', avo: '0030', kunde: 'Hellwig Hydraulik',        mat: 'V2A',  menge: 90,  kurz: 'Ventilsitz VS-5',      wert: 11200, dauerH: 3.5, restH: 3.5, planStart: H(4),  planEnde: H(9), bestand: 'direkt', released: true },
  { nr: 'FA-10502', avo: '0030', kunde: 'Pröll Feinwerktechnik',    mat: 'MS58', menge: 190, kurz: 'Düsenkörper DK-4',     wert: 4900,  dauerH: 2.5, restH: 2.5, planStart: H(4),  planEnde: H(10), bestand: 'direkt', released: true },
  { nr: 'FA-10507', avo: '0030', kunde: 'Pröll Feinwerktechnik',    mat: 'MS58', menge: 160, kurz: 'Düsenkörper DK-5',     wert: 4500,  dauerH: 2.5, restH: 2.5, planStart: H(5),  planEnde: H(11), bestand: 'direkt', released: true },
  { nr: 'FA-10511', avo: '0020', kunde: 'Vossberg Antriebstechnik', mat: 'ST42', menge: 120, kurz: 'Antriebswelle AW-222', wert: 18200, dauerH: 3.5, restH: 3.5, planStart: H(5),  planEnde: H(9), bestand: 'direkt', released: true },
  { nr: 'FA-10516', avo: '0020', kunde: 'Vossberg Antriebstechnik', mat: 'ST42', menge: 105, kurz: 'Lagerbock LB-16',      wert: 13100, dauerH: 3.0, restH: 3.0, planStart: H(6),  planEnde: H(10), bestand: 'direkt', released: true },
  { nr: 'FA-10520', avo: '0040', kunde: 'Nordmann Aerospace',       mat: 'TI5',  menge: 20,  kurz: 'Turbinenfuß TF-11',    wert: 40500, dauerH: 5.0, restH: 5.0, planStart: H(6),  planEnde: H(11), bestand: 'direkt', released: true },
  { nr: 'FA-10523', avo: '0030', kunde: 'Kästner Maschinenbau',     mat: 'AL60', menge: 60,  kurz: 'Adapterflansch AF-7',  wert: 7200,  dauerH: 3.0, restH: 3.0, planStart: H(7),  planEnde: H(12), bestand: 'direkt', released: true },

  // --- Kandidaten: warten auf Einplanung (Direkt-/Indirektbestand oder im Zulauf) ---
  { nr: 'FA-10428', avo: '0030', kunde: 'Nordmann Aerospace',   mat: 'TI5',  menge: 24, kurz: 'Turbinenfuß TF-9',    wert: 41200, dauerH: 5.0, restH: 5.0, planStart: H(8), planEnde: H(13),  bestand: 'direkt' },
  { nr: 'FA-10433', avo: '0020', kunde: 'Vossberg Antriebstechnik', mat: 'ST42', menge: 110, kurz: 'Antriebswelle AW-221', wert: 17900, dauerH: 3.5, restH: 3.5, planStart: H(9), planEnde: H(12),  bestand: 'direkt' },
  { nr: 'FA-10440', avo: '0030', kunde: 'Hellwig Hydraulik',    mat: 'C45',  menge: 80, kurz: 'Kolbenstange KS-09',  wert: 10300, dauerH: 4.0, restH: 4.0, planStart: H(9), planEnde: H(15),  bestand: 'indirekt', puffer: 'Pufferlager Halle 2' },
  { nr: 'FA-10447', avo: '0020', kunde: 'Kästner Maschinenbau', mat: 'AL60', menge: 65, kurz: 'Adapterflansch AF-6', wert: 6900,  dauerH: 3.0, restH: 3.0, planStart: H(10), planEnde: H(14),  bestand: 'indirekt', puffer: 'Pufferlager Halle 2' },
  { nr: 'FA-10451', avo: '0030', kunde: 'Pröll Feinwerktechnik', mat: 'MS58', menge: 200, kurz: 'Düsenkörper DK-2',   wert: 5200,  dauerH: 2.5, restH: 2.5, planStart: H(10), planEnde: H(17), bestand: 'route', step: 'Fräsen C42', eta: 11 },
  { nr: 'FA-10456', avo: '0040', kunde: 'Nordmann Aerospace',   mat: 'TI5',  menge: 18, kurz: 'Turbinenfuß TF-10',   wert: 39800, dauerH: 5.0, restH: 5.0, planStart: H(11), planEnde: H(14),  bestand: 'route', step: 'Härten extern', eta: 12 },
  { nr: 'FA-10462', avo: '0020', kunde: 'Barchitec Komponenten', mat: 'V2A', menge: 140, kurz: 'Gehäuseflansch GF-7', wert: 8800,  dauerH: 3.5, restH: 3.5, planStart: H(11), planEnde: H(19), bestand: 'route', step: 'Sägen AS-1', eta: 13 },
  { nr: 'FA-10468', avo: '0030', kunde: 'Hellwig Hydraulik',    mat: 'V2A',  menge: 95, kurz: 'Ventilsitz VS-4',     wert: 11600, dauerH: 4.0, restH: 4.0, planStart: H(12), planEnde: H(16), bestand: 'indirekt', puffer: 'Bereitstellung WS' },
  { nr: 'FA-10474', avo: '0020', kunde: 'Vossberg Antriebstechnik', mat: 'ST42', menge: 130, kurz: 'Lagerbock LB-15',  wert: 13400, dauerH: 3.5, restH: 3.5, planStart: H(12), planEnde: H(18), bestand: 'route', step: 'Drehen G220', eta: 14 },
  { nr: 'FA-10479', avo: '0030', kunde: 'Pröll Feinwerktechnik', mat: 'MS58', menge: 180, kurz: 'Düsenkörper DK-3',   wert: 4700,  dauerH: 2.5, restH: 2.5, planStart: H(13), planEnde: H(20), bestand: 'route', step: 'Fräsen C42', eta: 15 },
];

// ===== Arbeitsplan (Routing) je Fertigungsauftrag =====
// Jeder Schritt hat ein konkretes Arbeitssystem (wsId). Der Status ergibt sich aus dem
// Bestand: direkt/indirekt = vorgelagert erledigt, route = noch im Zulauf.
function buildArbeitsplan(o, i) {
  const needsHard = o.mat === 'TI5' || o.mat === 'V2A';
  const d = o.dauerH;
  const r = (x) => Math.max(0.3, Math.round(x * 10) / 10);
  const steps = [
    { key: 'lager',     avo: '0010', name: 'Materialfreigabe / Lager',  wsId: null,       wsLabel: 'Rohlager',          dauerH: r(0.3) },
    { key: 'saegen',    avo: '0020', name: 'Sägen / Zuschnitt',         wsId: 'WS-SG-01', dauerH: r(0.3 + d * 0.15) },
    { key: 'drehen',    avo: '0030', name: 'Drehen',                    wsId: o.drehWs,   dauerH: d },
    { key: 'fraesen',   avo: '0040', name: 'Fräsen Querbohrung',        wsId: 'WS-FR-11', dauerH: r(d * 0.55) },
  ];
  if (needsHard) steps.push({ key: 'waerme', avo: '0050', name: 'Wärmebehandlung', wsId: null, wsLabel: 'Härterei (extern)', dauerH: 6.0 });
  steps.push({ key: 'entgraten', avo: needsHard ? '0060' : '0050', name: 'Entgraten / Gleitschleifen', wsId: 'WS-EN-01', dauerH: r(0.4 + d * 0.1) });
  steps.push({ key: 'pruefen',   avo: needsHard ? '0070' : '0060', name: 'Endprüfung / Messraum',      wsId: 'WS-MR-01', dauerH: r(0.3 + d * 0.08) });

  // Anzeigename des Arbeitssystems je Schritt
  steps.forEach(s => { if (s.wsId) { const w = WORK_SYSTEMS.find(x => x.id === s.wsId); s.wsLabel = w ? w.name : s.wsId; } });

  // aktuelle physische Position des Auftrags in der Route (über alle Stufen verteilt)
  const drehIdx = steps.findIndex(s => s.key === 'drehen');
  const lastIdx = steps.length - 1;
  let currentIdx;
  if (o.bestand === 'route') currentIdx = (o.eta != null && o.eta >= 13) ? 0 : drehIdx - 1; // Lager (weit) oder Sägen (nah)
  else if (o.bestand === 'indirekt') currentIdx = drehIdx;                                    // im Puffer vor dem Drehen
  else if (o.released) currentIdx = Math.min(drehIdx + ((i || 0) % 4), lastIdx);               // freigegeben: über Folgestufen verteilt
  else currentIdx = drehIdx;                                                                   // direkt: am Drehzentrum bereit

  steps.forEach((s, i) => {
    if (i < currentIdx) s.status = 'erledigt';
    else if (i === currentIdx) s.status = (o.bestand === 'route') ? 'läuft' : 'bereit';
    else s.status = 'offen';
  });
  return steps;
}
ORDERS.forEach((o, i) => {
  o.drehWs = DREH_WS(i);
  // Jahresbedarf (Stück/Jahr) für die Losgrößenrechnung – aus der Losgröße abgeleitet
  o.jahresbedarf = Math.round(o.menge * (18 + (i % 7) * 4));
  o.arbeitsplan = buildArbeitsplan(o, i);
  // aktuelle physische Position (wo der Auftrag gerade ist) für die Anzeige in Folgesystemen
  const cur = o.arbeitsplan.find(s => s.status === 'läuft' || s.status === 'bereit');
  o.currentStepName = cur ? cur.name : o.arbeitsplan[o.arbeitsplan.length - 1].name;
  o.currentStepWs = cur ? cur.wsLabel : '';
  if (o.bestand === 'route' && cur) { o.step = cur.name; o.stepWs = cur.wsLabel; }
  // Gesamte verbleibende Restarbeit = alle noch nicht erledigten Vorgänge im Arbeitsplan
  o.restGesamtH = o.arbeitsplan.filter(s => s.status !== 'erledigt').reduce((a, s) => a + s.dauerH, 0);
});

// ===== Vorgänge je Arbeitssystem aus den Arbeitsplänen ableiten =====
// Ein "Task" = (Auftrag, sein Arbeitsplan-Schritt an diesem System). Nur noch NICHT erledigte Schritte.
// Bestand/Status wird je System aus dem Schritt-Status abgeleitet → ein Auftrag ist nur an EINEM System direkt.
const TASKS_BY_SYSTEM = {};
WORK_SYSTEMS.forEach(w => {
  TASKS_BY_SYSTEM[w.id] = ORDERS
    .map(o => ({ o, st: o.arbeitsplan.find(s => s.wsId === w.id) }))
    .filter(x => x.st && x.st.status !== 'erledigt')
    .map(({ o, st }) => {
      const here = st.status === 'bereit' || st.status === 'läuft';
      const bestand = here ? (o.bestand === 'indirekt' ? 'indirekt' : 'direkt') : 'route';
      const released = !!o.released && here;
      return {
        ...o, avo: st.avo, dauerH: st.dauerH, stepKey: st.key,
        baseMenge: o.menge, einzelzeitH: st.dauerH / Math.max(1, o.menge), // Einzelzeit (h/Stück) am System
        bestand, released,
        step: o.currentStepName, stepWs: o.currentStepWs,
      };
    });
});

// ===== Übergangszeiten & Auftragsreichweite =====
// Min-Übergangszeit (h) je Arbeitssystem: minimale Liege-/Transportzeit bis zum nächsten System
const TRANSITION_DEFAULT = { 'WS-SG-01': 2, 'WS-DZ-04': 2, 'WS-DZ-02': 2, 'WS-FR-11': 2, 'WS-EN-01': 2, 'WS-MR-01': 2 };
// Ø Reichweite der letzten 4 Wochen (Tage) je System — Historie (KW-Werte, neueste zuletzt)
const REACH_HISTORY = {
  'WS-SG-01': [1.8, 2.2, 1.6, 1.9],
  'WS-DZ-04': [2.5, 2.1, 2.7, 2.3],
  'WS-DZ-02': [5.1, 4.6, 5.4, 4.8],
  'WS-FR-11': [9.2, 8.6, 7.9, 8.3],
  'WS-EN-01': [1.2, 0.9, 1.4, 1.1],
  'WS-MR-01': [2.0, 1.7, 2.3, 1.9],
};
// Auftragsbestand (Arbeitsinhalt in h) für nicht-aktive Systeme (aktives wird live gerechnet)
const STATIC_BACKLOG_H = { 'WS-SG-01': 34, 'WS-DZ-04': 120, 'WS-DZ-02': 96, 'WS-FR-11': 168, 'WS-EN-01': 22, 'WS-MR-01': 40 };
// Live-Auftragsbestand des aktiven Systems: Summe Arbeitsinhalt der offenen Vorgänge an diesem System
function liveBacklogH(wsId) {
  const tasks = (wsId && TASKS_BY_SYSTEM[wsId]) || [];
  return tasks.filter(o => !o.released).reduce((a, o) => a + o.dauerH, 0);
}

// Früheste Ankunft eines Auftrags an System wsId (h ab Horizont): Summe aus Dauer + Übergangszeit
// aller Arbeitsplan-Schritte von der aktuellen Position bis zu diesem System.
function arrivalOffsetH(o, wsId, transitionBySystem) {
  const ap = o.arbeitsplan;
  const targetIdx = ap.findIndex(s => s.wsId === wsId);
  if (targetIdx < 0) return 0;
  let startIdx = ap.findIndex(s => s.status === 'bereit' || s.status === 'läuft');
  if (startIdx < 0) startIdx = 0;
  if (targetIdx <= startIdx) return 0; // bereits am System (oder davor) → sofort verfügbar
  let t = 0;
  for (let i = startIdx; i < targetIdx; i++) {
    t += ap[i].dauerH;
    if (ap[i].wsId) t += (transitionBySystem[ap[i].wsId] || 0);
  }
  return t;
}

// Dummy-Kalender: Bezugs-Montag für Datumsangaben
const BASE_MONDAY = new Date(2026, 5, 8); // Mo, 08.06.2026
const WD = ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'];
function dateFromH(h) {
  const d = new Date(BASE_MONDAY);
  d.setDate(d.getDate() + Math.floor(h / 24));
  return d;
}
// Datums-Label, z.B. "Di 09.06." (mit Wochentag) oder "09.06.26"
function fmtDate(h, withWeekday) {
  const d = dateFromH(h);
  const dd = String(d.getDate()).padStart(2, '0');
  const mm = String(d.getMonth() + 1).padStart(2, '0');
  const yy = String(d.getFullYear()).slice(2);
  return withWeekday ? `${WD[d.getDay()]} ${dd}.${mm}.` : `${dd}.${mm}.${yy}`;
}

// ===== Stammdaten für Losgrößenberechnung (Andler) =====
// Globale Kostensätze (im Popup einsehbar/anpassbar)
const STAMMDATEN = {
  zinssatz: 18,            // Lagerhaltungs-/Zinssatz % p.a.
  lohnkosten: 42,         // Lohnkosten €/h (Werker)
  maschinenstundensatz: 95, // Maschinenstundensatz €/h
};
// Teilewert (Materialeinzelkosten €/Stück) je Werkstoff – aus „Stammdaten"
const TEILEWERT = { ST42: 14.5, C45: 9.8, AL70: 28.0, AL60: 11.2, V2A: 22.5, MS58: 7.4, TI5: 96.0 };
// Andler-Losgröße: q* = sqrt( (2 · Jahresbedarf · Rüstkosten) / (Zinssatz · Stückwert) )
function andlerOptimum({ jahresbedarf, ruestkosten, stueckwert, zinssatz }) {
  const ch = (zinssatz / 100) * stueckwert; // Lagerkostensatz €/Stück·Jahr
  if (ch <= 0 || jahresbedarf <= 0) return { q: 0, ch };
  return { q: Math.sqrt((2 * jahresbedarf * ruestkosten) / ch), ch };
}
// Gesamtkosten p.a. bei Losgröße q (Rüst-/Bestellkosten + Lagerkosten)
function losKosten(q, { jahresbedarf, ruestkosten, ch }) {
  if (q <= 0) return Infinity;
  return (jahresbedarf / q) * ruestkosten + (q / 2) * ch;
}

Object.assign(window, {
  SHIFT_HOURS, MATERIALS, setupMinutes, baseSetupMinutes, WORK_SYSTEMS, SHIFTS, SHIFT_NAMES, DAYS, CUSTOMERS, ORDERS, H, fmtDate, dateFromH,
  STAMMDATEN, TEILEWERT, andlerOptimum, losKosten,
  TRANSITION_DEFAULT, REACH_HISTORY, STATIC_BACKLOG_H, liveBacklogH, TASKS_BY_SYSTEM, arrivalOffsetH,
});
