export type OeeMeasurement = {
  id: string
  oee_station_id: string
  shift_or_session: string | null
  planned_production_time_min: number | null
  actual_run_time_min: number | null
  total_pieces: number | null
  good_pieces: number | null
  reject_pieces: number | null
  ideal_cycle_time_sec: number | null
  breakdown_min: number | null
  setup_min: number | null
  micro_stop_min: number | null
  speed_loss_min: number | null
  quality_loss_count: number | null
}

export type OeeMeasurementInput = {
  shift_or_session: string | null
  planned_production_time_min: number | null
  actual_run_time_min: number | null
  total_pieces: number | null
  good_pieces: number | null
  reject_pieces: number | null
  ideal_cycle_time_sec: number | null
  breakdown_min: number | null
  setup_min: number | null
  micro_stop_min: number | null
  speed_loss_min: number | null
  quality_loss_count: number | null
}

export type MeasurementValidationError =
  | 'planned_time_negative'
  | 'actual_time_negative'
  | 'actual_exceeds_planned'
  | 'good_exceeds_total'
  | 'pieces_negative'
  | 'cycle_time_negative'

export function validateMeasurementInput(
  input: OeeMeasurementInput,
): { ok: true } | { ok: false; error: MeasurementValidationError } {
  if ((input.planned_production_time_min ?? 0) < 0) return { ok: false, error: 'planned_time_negative' }
  if ((input.actual_run_time_min ?? 0) < 0) return { ok: false, error: 'actual_time_negative' }
  if (
    input.planned_production_time_min !== null &&
    input.actual_run_time_min !== null &&
    input.actual_run_time_min > input.planned_production_time_min
  ) {
    return { ok: false, error: 'actual_exceeds_planned' }
  }
  if (
    input.good_pieces !== null &&
    input.total_pieces !== null &&
    input.good_pieces > input.total_pieces
  ) {
    return { ok: false, error: 'good_exceeds_total' }
  }
  if (
    (input.total_pieces ?? 0) < 0 ||
    (input.good_pieces ?? 0) < 0 ||
    (input.reject_pieces ?? 0) < 0
  ) {
    return { ok: false, error: 'pieces_negative' }
  }
  if ((input.ideal_cycle_time_sec ?? 0) < 0) return { ok: false, error: 'cycle_time_negative' }
  return { ok: true }
}

export type StationKpis = {
  plannedMin: number
  actualMin: number
  totalPieces: number
  goodPieces: number
  rejectPieces: number
  idealCycleSec: number | null
  theoreticalPieces: number
  availability: number
  performance: number
  quality: number
  oee: number
}

export function calculateStationKpis(measurements: OeeMeasurement[]): StationKpis {
  let plannedMin = 0
  let actualMin = 0
  let totalPieces = 0
  let goodPieces = 0
  let rejectPieces = 0
  let weightedCycleSecXTime = 0
  let weightedTimeForCycle = 0

  for (const m of measurements) {
    plannedMin += m.planned_production_time_min ?? 0
    actualMin += m.actual_run_time_min ?? 0
    totalPieces += m.total_pieces ?? 0
    goodPieces += m.good_pieces ?? 0
    rejectPieces += m.reject_pieces ?? 0
    if (m.ideal_cycle_time_sec && m.actual_run_time_min) {
      weightedCycleSecXTime += m.ideal_cycle_time_sec * m.actual_run_time_min
      weightedTimeForCycle += m.actual_run_time_min
    }
  }

  const idealCycleSec =
    weightedTimeForCycle > 0 ? weightedCycleSecXTime / weightedTimeForCycle : null
  const theoreticalPieces = idealCycleSec && idealCycleSec > 0 ? (actualMin * 60) / idealCycleSec : 0

  const availability = plannedMin > 0 ? Math.min(1, actualMin / plannedMin) : 0
  const performance = theoreticalPieces > 0 ? Math.min(1, totalPieces / theoreticalPieces) : 0
  const quality = totalPieces > 0 ? Math.min(1, goodPieces / totalPieces) : 0
  const oee = availability * performance * quality

  return {
    plannedMin,
    actualMin,
    totalPieces,
    goodPieces,
    rejectPieces,
    idealCycleSec,
    theoreticalPieces,
    availability,
    performance,
    quality,
    oee,
  }
}

export type AnalysisKpis = StationKpis & {
  stationCount: number
}

export function aggregateAnalysisKpis(
  measurementsByStation: Map<string, OeeMeasurement[]>,
): AnalysisKpis {
  let plannedMin = 0
  let actualMin = 0
  let totalPieces = 0
  let goodPieces = 0
  let rejectPieces = 0
  let weightedCycleSecXTime = 0
  let weightedTimeForCycle = 0
  let stationCount = 0

  for (const measurements of measurementsByStation.values()) {
    stationCount += 1
    for (const m of measurements) {
      plannedMin += m.planned_production_time_min ?? 0
      actualMin += m.actual_run_time_min ?? 0
      totalPieces += m.total_pieces ?? 0
      goodPieces += m.good_pieces ?? 0
      rejectPieces += m.reject_pieces ?? 0
      if (m.ideal_cycle_time_sec && m.actual_run_time_min) {
        weightedCycleSecXTime += m.ideal_cycle_time_sec * m.actual_run_time_min
        weightedTimeForCycle += m.actual_run_time_min
      }
    }
  }

  const idealCycleSec =
    weightedTimeForCycle > 0 ? weightedCycleSecXTime / weightedTimeForCycle : null
  const theoreticalPieces = idealCycleSec && idealCycleSec > 0 ? (actualMin * 60) / idealCycleSec : 0

  const availability = plannedMin > 0 ? Math.min(1, actualMin / plannedMin) : 0
  const performance = theoreticalPieces > 0 ? Math.min(1, totalPieces / theoreticalPieces) : 0
  const quality = totalPieces > 0 ? Math.min(1, goodPieces / totalPieces) : 0
  const oee = availability * performance * quality

  return {
    plannedMin,
    actualMin,
    totalPieces,
    goodPieces,
    rejectPieces,
    idealCycleSec,
    theoreticalPieces,
    availability,
    performance,
    quality,
    oee,
    stationCount,
  }
}

export type LossBreakdownMin = {
  breakdown: number
  setup: number
  microStop: number
  speedLoss: number
  qualityLoss: number
  other: number
}

export function aggregateLossBreakdown(measurements: OeeMeasurement[]): LossBreakdownMin {
  let breakdown = 0
  let setup = 0
  let microStop = 0
  let speedLoss = 0
  let qualityLossPieces = 0
  let weightedCycleSecXTime = 0
  let weightedTimeForCycle = 0
  for (const m of measurements) {
    breakdown += m.breakdown_min ?? 0
    setup += m.setup_min ?? 0
    microStop += m.micro_stop_min ?? 0
    speedLoss += m.speed_loss_min ?? 0
    qualityLossPieces += m.quality_loss_count ?? 0
    if (m.ideal_cycle_time_sec && m.actual_run_time_min) {
      weightedCycleSecXTime += m.ideal_cycle_time_sec * m.actual_run_time_min
      weightedTimeForCycle += m.actual_run_time_min
    }
  }
  const idealCycleSec = weightedTimeForCycle > 0 ? weightedCycleSecXTime / weightedTimeForCycle : 0
  const qualityLossMin = idealCycleSec > 0 ? (qualityLossPieces * idealCycleSec) / 60 : 0
  return {
    breakdown,
    setup,
    microStop,
    speedLoss,
    qualityLoss: qualityLossMin,
    other: 0,
  }
}

// KAR-704 C4: single source of truth in ./engine. Re-exported here so existing
// importers (and the measurement-engine test) keep working without a duplicate.
export { formatPercent } from './engine'

export const MEASUREMENT_VALIDATION_LABEL_DE: Record<MeasurementValidationError, string> = {
  planned_time_negative: 'Geplante Zeit darf nicht negativ sein',
  actual_time_negative: 'Tatsächliche Laufzeit darf nicht negativ sein',
  actual_exceeds_planned: 'Tatsächliche Laufzeit > geplante Zeit',
  good_exceeds_total: 'Gutmenge > Gesamtmenge',
  pieces_negative: 'Stückzahlen dürfen nicht negativ sein',
  cycle_time_negative: 'Zykluszeit darf nicht negativ sein',
}
