// 생산 현황판 KPI 강화 설정
// 상용 MES 대비 개선사항 Phase 2

/**
 * ═══════════════════════════════════════════════════════════════════
 * 생산 KPI (Key Performance Indicators) 관리
 * ═══════════════════════════════════════════════════════════════════
 *
 * 목적: 생산 성과 실시간 모니터링 및 의사결정 지원
 *       - OEE (종합설비효율) 모니터링
 *       - 생산성 지표 추적
 *       - 품질 지표 관리
 *       - 납기 준수율 모니터링
 *
 * ═══════════════════════════════════════════════════════════════════
 */

// KPI 카테고리 정의
export const kpiCategories = {
  PRODUCTIVITY: {
    code: 'PRODUCTIVITY',
    name: '생산성',
    description: '생산 효율 및 산출량 관련 지표',
    color: 'bg-blue-500',
    icon: 'TrendingUp',
  },
  QUALITY: {
    code: 'QUALITY',
    name: '품질',
    description: '품질 수준 및 불량률 관련 지표',
    color: 'bg-green-500',
    icon: 'ShieldCheck',
  },
  DELIVERY: {
    code: 'DELIVERY',
    name: '납기',
    description: '납기 준수 및 리드타임 관련 지표',
    color: 'bg-purple-500',
    icon: 'Clock',
  },
  COST: {
    code: 'COST',
    name: '원가',
    description: '원가 효율성 관련 지표',
    color: 'bg-orange-500',
    icon: 'DollarSign',
  },
  SAFETY: {
    code: 'SAFETY',
    name: '안전',
    description: '작업 안전 관련 지표',
    color: 'bg-red-500',
    icon: 'AlertTriangle',
  },
};

// KPI 정의
export const kpiDefinitions = {
  // ═══════════════════════════════════════
  // 생산성 KPI
  // ═══════════════════════════════════════
  OEE: {
    code: 'OEE',
    name: '종합설비효율 (OEE)',
    fullName: 'Overall Equipment Effectiveness',
    category: 'PRODUCTIVITY',
    formula: '가동률 × 성능효율 × 양품률',
    unit: '%',
    target: 85,
    warning: 75,
    critical: 65,
    components: ['AVAILABILITY', 'PERFORMANCE', 'QUALITY_RATE'],
    description: '설비의 종합적인 효율성을 측정하는 핵심 지표',
  },
  AVAILABILITY: {
    code: 'AVAILABILITY',
    name: '가동률',
    fullName: 'Availability',
    category: 'PRODUCTIVITY',
    formula: '(계획운전시간 - 정지시간) / 계획운전시간 × 100',
    unit: '%',
    target: 95,
    warning: 90,
    critical: 85,
    description: '설비가 실제로 가동된 시간 비율',
  },
  PERFORMANCE: {
    code: 'PERFORMANCE',
    name: '성능효율',
    fullName: 'Performance Efficiency',
    category: 'PRODUCTIVITY',
    formula: '(이론 사이클타임 × 생산수량) / 가동시간 × 100',
    unit: '%',
    target: 95,
    warning: 85,
    critical: 75,
    description: '설비의 이론적 생산 능력 대비 실제 생산 비율',
  },
  PRODUCTION_VOLUME: {
    code: 'PRODUCTION_VOLUME',
    name: '생산량',
    category: 'PRODUCTIVITY',
    formula: '완료 수량 합계',
    unit: 'EA',
    target: null, // 동적 목표
    description: '기간 내 총 생산 수량',
  },
  PRODUCTION_PLAN_RATE: {
    code: 'PRODUCTION_PLAN_RATE',
    name: '생산계획 달성률',
    category: 'PRODUCTIVITY',
    formula: '실제 생산량 / 계획 생산량 × 100',
    unit: '%',
    target: 100,
    warning: 95,
    critical: 90,
    description: '생산 계획 대비 실제 달성률',
  },
  CYCLE_TIME: {
    code: 'CYCLE_TIME',
    name: '사이클 타임',
    category: 'PRODUCTIVITY',
    formula: '가동시간 / 생산수량',
    unit: '분/EA',
    target: null, // 제품별 상이
    description: '단위 제품 생산에 소요되는 평균 시간',
  },

  // ═══════════════════════════════════════
  // 품질 KPI
  // ═══════════════════════════════════════
  QUALITY_RATE: {
    code: 'QUALITY_RATE',
    name: '양품률',
    fullName: 'Quality Rate',
    category: 'QUALITY',
    formula: '(생산수량 - 불량수량) / 생산수량 × 100',
    unit: '%',
    target: 99,
    warning: 97,
    critical: 95,
    description: '생산된 제품 중 양품의 비율',
  },
  DEFECT_RATE: {
    code: 'DEFECT_RATE',
    name: '불량률',
    category: 'QUALITY',
    formula: '불량수량 / 생산수량 × 100',
    unit: '%',
    target: 1,
    warning: 3,
    critical: 5,
    inverse: true, // 낮을수록 좋음
    description: '생산된 제품 중 불량품의 비율',
  },
  FIRST_PASS_YIELD: {
    code: 'FIRST_PASS_YIELD',
    name: '초도 합격률 (FPY)',
    fullName: 'First Pass Yield',
    category: 'QUALITY',
    formula: '초도검사 합격수량 / 검사수량 × 100',
    unit: '%',
    target: 98,
    warning: 95,
    critical: 90,
    description: '최초 검사에서 합격한 비율 (재작업 제외)',
  },
  CUSTOMER_CLAIM_RATE: {
    code: 'CUSTOMER_CLAIM_RATE',
    name: '고객 클레임률',
    category: 'QUALITY',
    formula: '클레임 건수 / 출하 건수 × 100',
    unit: '%',
    target: 0.1,
    warning: 0.5,
    critical: 1,
    inverse: true,
    description: '고객 클레임 발생 비율',
  },

  // ═══════════════════════════════════════
  // 납기 KPI
  // ═══════════════════════════════════════
  ON_TIME_DELIVERY: {
    code: 'ON_TIME_DELIVERY',
    name: '납기 준수율',
    fullName: 'On-Time Delivery Rate',
    category: 'DELIVERY',
    formula: '납기 내 완료 건수 / 전체 완료 건수 × 100',
    unit: '%',
    target: 98,
    warning: 95,
    critical: 90,
    description: '약속된 납기 내 납품된 비율',
  },
  LEAD_TIME: {
    code: 'LEAD_TIME',
    name: '생산 리드타임',
    category: 'DELIVERY',
    formula: '완료일 - 시작일',
    unit: '일',
    target: null, // 제품별 상이
    inverse: true,
    description: '수주에서 출하까지 소요 시간',
  },
  WIP_TURNOVER: {
    code: 'WIP_TURNOVER',
    name: '재공 회전율',
    category: 'DELIVERY',
    formula: '완성품 출고액 / 평균 재공재고액',
    unit: '회',
    target: 12,
    warning: 8,
    critical: 4,
    description: '재공재고의 회전 속도',
  },

  // ═══════════════════════════════════════
  // 원가 KPI
  // ═══════════════════════════════════════
  COST_VARIANCE: {
    code: 'COST_VARIANCE',
    name: '원가 차이율',
    category: 'COST',
    formula: '(표준원가 - 실제원가) / 표준원가 × 100',
    unit: '%',
    target: 0,
    warning: -5,
    critical: -10,
    description: '표준원가 대비 실제원가 차이',
  },
  MATERIAL_LOSS_RATE: {
    code: 'MATERIAL_LOSS_RATE',
    name: '자재 로스율',
    category: 'COST',
    formula: '(투입량 - 산출량) / 투입량 × 100',
    unit: '%',
    target: 2,
    warning: 5,
    critical: 8,
    inverse: true,
    description: '자재 투입 대비 손실 비율',
  },
  LABOR_PRODUCTIVITY: {
    code: 'LABOR_PRODUCTIVITY',
    name: '노동 생산성',
    category: 'COST',
    formula: '생산량 / 투입 인시',
    unit: 'EA/인시',
    target: null,
    description: '투입 인력 대비 생산량',
  },
};

// 대시보드 레이아웃 설정
export const dashboardLayout = {
  // 상단 요약 카드
  summaryCards: [
    { kpi: 'OEE', span: 1 },
    { kpi: 'PRODUCTION_PLAN_RATE', span: 1 },
    { kpi: 'QUALITY_RATE', span: 1 },
    { kpi: 'ON_TIME_DELIVERY', span: 1 },
  ],
  // 중단 차트
  charts: [
    {
      type: 'line',
      title: 'OEE 추이',
      kpis: ['OEE', 'AVAILABILITY', 'PERFORMANCE', 'QUALITY_RATE'],
      span: 2,
    },
    {
      type: 'bar',
      title: '공정별 생산량',
      dataSource: 'productionByProcess',
      span: 1,
    },
    {
      type: 'pie',
      title: '불량 유형별 현황',
      dataSource: 'defectsByType',
      span: 1,
    },
  ],
  // 하단 테이블
  tables: [
    {
      title: '작업지시 현황',
      dataSource: 'workOrders',
      columns: ['workOrderNo', 'productName', 'quantity', 'progress', 'status'],
    },
    {
      title: '품질 이슈',
      dataSource: 'qualityIssues',
      columns: ['issueNo', 'product', 'defectType', 'status', 'assignee'],
    },
  ],
};

// KPI 상태 판정
export const kpiStatusLevels = {
  EXCELLENT: { code: 'EXCELLENT', name: '우수', color: 'bg-green-500 text-white' },
  GOOD: { code: 'GOOD', name: '양호', color: 'bg-blue-500 text-white' },
  WARNING: { code: 'WARNING', name: '주의', color: 'bg-yellow-500 text-black' },
  CRITICAL: { code: 'CRITICAL', name: '위험', color: 'bg-red-500 text-white' },
};

/**
 * KPI 상태 판정
 * @param {string} kpiCode - KPI 코드
 * @param {number} value - 측정값
 * @returns {object} 상태 정보
 */
export const evaluateKpiStatus = (kpiCode, value) => {
  const kpi = kpiDefinitions[kpiCode];
  if (!kpi) return { status: kpiStatusLevels.GOOD, message: '정의되지 않은 KPI' };

  const { target, warning, critical, inverse } = kpi;

  if (inverse) {
    // 낮을수록 좋은 지표 (불량률 등)
    if (value <= target) return { status: kpiStatusLevels.EXCELLENT, message: '목표 달성' };
    if (value <= warning) return { status: kpiStatusLevels.GOOD, message: '양호' };
    if (value <= critical) return { status: kpiStatusLevels.WARNING, message: '주의 필요' };
    return { status: kpiStatusLevels.CRITICAL, message: '개선 필요' };
  } else {
    // 높을수록 좋은 지표 (가동률 등)
    if (value >= target) return { status: kpiStatusLevels.EXCELLENT, message: '목표 달성' };
    if (value >= warning) return { status: kpiStatusLevels.GOOD, message: '양호' };
    if (value >= critical) return { status: kpiStatusLevels.WARNING, message: '주의 필요' };
    return { status: kpiStatusLevels.CRITICAL, message: '개선 필요' };
  }
};

/**
 * OEE 계산
 * @param {number} availability - 가동률 (%)
 * @param {number} performance - 성능효율 (%)
 * @param {number} qualityRate - 양품률 (%)
 * @returns {object} OEE 계산 결과
 */
export const calculateOEE = (availability, performance, qualityRate) => {
  const oee = (availability * performance * qualityRate) / 10000;

  return {
    oee: Math.round(oee * 100) / 100,
    availability,
    performance,
    qualityRate,
    status: evaluateKpiStatus('OEE', oee),
    worldClass: oee >= 85,
    breakdown: {
      availabilityContribution: Math.round(availability / 3 * 10) / 10,
      performanceContribution: Math.round(performance / 3 * 10) / 10,
      qualityContribution: Math.round(qualityRate / 3 * 10) / 10,
    },
  };
};

/**
 * 생산 실적 기반 KPI 계산
 * @param {Array} workResults - 작업 실적 목록
 * @param {object} options - 계산 옵션
 * @returns {object} KPI 계산 결과
 */
export const calculateProductionKpis = (workResults, options = {}) => {
  const { period = 'daily' } = options;

  // 기본 집계
  const totalProduced = workResults.reduce((sum, r) => sum + (r.completedQty || 0), 0);
  const totalPlanned = workResults.reduce((sum, r) => sum + (r.plannedQty || 0), 0);
  const totalDefects = workResults.reduce((sum, r) => sum + (r.defectQty || 0), 0);
  const completedOnTime = workResults.filter(r =>
    r.status === '완료' && new Date(r.completedAt) <= new Date(r.dueDate)
  ).length;

  // 시간 집계 (분 단위)
  const totalPlannedTime = workResults.reduce((sum, r) => sum + (r.plannedTime || 0), 0);
  const totalActualTime = workResults.reduce((sum, r) => sum + (r.actualTime || 0), 0);
  const totalDowntime = workResults.reduce((sum, r) => sum + (r.downtime || 0), 0);

  // KPI 계산
  const kpis = {
    // 생산량
    productionVolume: {
      value: totalProduced,
      target: totalPlanned,
      achievement: totalPlanned > 0 ? Math.round(totalProduced / totalPlanned * 100) : 0,
    },

    // 생산계획 달성률
    productionPlanRate: {
      value: totalPlanned > 0 ? Math.round(totalProduced / totalPlanned * 100) : 0,
      status: evaluateKpiStatus('PRODUCTION_PLAN_RATE',
        totalPlanned > 0 ? totalProduced / totalPlanned * 100 : 0
      ),
    },

    // 양품률
    qualityRate: {
      value: totalProduced > 0
        ? Math.round((totalProduced - totalDefects) / totalProduced * 1000) / 10
        : 100,
      status: evaluateKpiStatus('QUALITY_RATE',
        totalProduced > 0 ? (totalProduced - totalDefects) / totalProduced * 100 : 100
      ),
    },

    // 불량률
    defectRate: {
      value: totalProduced > 0
        ? Math.round(totalDefects / totalProduced * 1000) / 10
        : 0,
      defectCount: totalDefects,
      status: evaluateKpiStatus('DEFECT_RATE',
        totalProduced > 0 ? totalDefects / totalProduced * 100 : 0
      ),
    },

    // 가동률
    availability: {
      value: totalPlannedTime > 0
        ? Math.round((totalPlannedTime - totalDowntime) / totalPlannedTime * 1000) / 10
        : 100,
      status: evaluateKpiStatus('AVAILABILITY',
        totalPlannedTime > 0 ? (totalPlannedTime - totalDowntime) / totalPlannedTime * 100 : 100
      ),
    },

    // 성능효율
    performance: {
      value: totalActualTime > 0
        ? Math.round(totalPlannedTime / totalActualTime * 1000) / 10
        : 100,
      status: evaluateKpiStatus('PERFORMANCE',
        totalActualTime > 0 ? totalPlannedTime / totalActualTime * 100 : 100
      ),
    },

    // 납기 준수율
    onTimeDelivery: {
      value: workResults.length > 0
        ? Math.round(completedOnTime / workResults.filter(r => r.status === '완료').length * 1000) / 10 || 0
        : 0,
      onTimeCount: completedOnTime,
      totalCompleted: workResults.filter(r => r.status === '완료').length,
      status: evaluateKpiStatus('ON_TIME_DELIVERY',
        workResults.filter(r => r.status === '완료').length > 0
          ? completedOnTime / workResults.filter(r => r.status === '완료').length * 100
          : 100
      ),
    },
  };

  // OEE 계산
  kpis.oee = calculateOEE(
    kpis.availability.value,
    kpis.performance.value,
    kpis.qualityRate.value
  );

  return {
    period,
    calculatedAt: new Date().toISOString(),
    workOrderCount: workResults.length,
    kpis,
  };
};

/**
 * 공정별 KPI 집계
 * @param {Array} workResults - 작업 실적 목록
 * @returns {object} 공정별 KPI
 */
export const calculateKpiByProcess = (workResults) => {
  const byProcess = {};

  workResults.forEach(result => {
    const process = result.processName || result.processCode || '기타';
    if (!byProcess[process]) {
      byProcess[process] = {
        processName: process,
        results: [],
      };
    }
    byProcess[process].results.push(result);
  });

  // 공정별 KPI 계산
  Object.keys(byProcess).forEach(process => {
    byProcess[process].kpis = calculateProductionKpis(byProcess[process].results);
    delete byProcess[process].results; // 원본 데이터 제거
  });

  return byProcess;
};

/**
 * KPI 트렌드 분석
 * @param {Array} historicalData - 과거 KPI 데이터 [{ date, kpis }]
 * @param {string} kpiCode - 분석할 KPI
 * @returns {object} 트렌드 분석 결과
 */
export const analyzeKpiTrend = (historicalData, kpiCode) => {
  if (historicalData.length < 2) {
    return { trend: 'insufficient_data', message: '데이터 부족' };
  }

  const values = historicalData.map(d => d.kpis?.[kpiCode]?.value || 0);
  const recentAvg = values.slice(-3).reduce((a, b) => a + b, 0) / Math.min(3, values.length);
  const previousAvg = values.slice(0, -3).reduce((a, b) => a + b, 0) / Math.max(1, values.length - 3);

  const changePercent = previousAvg > 0
    ? Math.round((recentAvg - previousAvg) / previousAvg * 1000) / 10
    : 0;

  let trend, message;
  if (changePercent >= 5) {
    trend = 'improving';
    message = `${changePercent}% 개선`;
  } else if (changePercent <= -5) {
    trend = 'declining';
    message = `${Math.abs(changePercent)}% 하락`;
  } else {
    trend = 'stable';
    message = '안정적';
  }

  return {
    trend,
    message,
    changePercent,
    recentAvg: Math.round(recentAvg * 10) / 10,
    previousAvg: Math.round(previousAvg * 10) / 10,
    dataPoints: values.length,
  };
};

export default {
  kpiCategories,
  kpiDefinitions,
  dashboardLayout,
  kpiStatusLevels,
  evaluateKpiStatus,
  calculateOEE,
  calculateProductionKpis,
  calculateKpiByProcess,
  analyzeKpiTrend,
};
