import type { KR, ProjectStatus, Checkin } from '@/types/database'; export function getTodayInTokyo(): string { const now = new Date(); const tokyoTime = new Date(now.toLocaleString('en-US', { timeZone: 'Asia/Tokyo' })); return tokyoTime.toISOString().split('T')[0]; } export function calculateProgress(kr: KR): number { if (kr.direction === 'increase') { return kr.target_value > 0 ? kr.current_value / kr.target_value : 0; } else { return kr.current_value > 0 ? kr.target_value / kr.current_value : 0; } } export function calculateExpectedProgress(kr: KR): number { const today = getTodayInTokyo(); const start = new Date(kr.period_start); const end = new Date(kr.period_end); const current = new Date(today); const totalDays = Math.ceil((end.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1; const elapsedDays = Math.max(0, Math.ceil((current.getTime() - start.getTime()) / (1000 * 60 * 60 * 24)) + 1); return Math.min(1, elapsedDays / totalDays); } export function determineKRStatus( kr: KR, recentCheckins: Checkin[] = [] ): ProjectStatus { const progress = calculateProgress(kr); const expectedProgress = calculateExpectedProgress(kr); const progressGap = expectedProgress - progress; const consecutiveYellows = recentCheckins .slice(0, 2) .filter(c => c.status_snapshot === 'yellow').length >= 2; if (consecutiveYellows) { return 'red'; } if (kr.confidence < 50 || progressGap > 0.15) { return 'red'; } if ((kr.confidence >= 50 && kr.confidence < 80) || (progressGap > 0.05 && progressGap <= 0.15)) { return 'yellow'; } if (kr.confidence >= 80 && progressGap <= 0.05) { return 'green'; } return 'yellow'; } export function determineProjectStatus(krs: KR[]): ProjectStatus { if (krs.length === 0) return 'green'; const redCount = krs.filter(kr => kr.status === 'red').length; const yellowCount = krs.filter(kr => kr.status === 'yellow').length; if (redCount > 0) return 'red'; const yellowRatio = yellowCount / krs.length; if (yellowRatio > 0.3) return 'red'; if (yellowCount > 0) return 'yellow'; return 'green'; } export function formatDateRange(start: string, end: string): string { const startDate = new Date(start); const endDate = new Date(end); const formatOptions: Intl.DateTimeFormatOptions = { month: 'short', day: 'numeric' }; return `${startDate.toLocaleDateString('zh-CN', formatOptions)} - ${endDate.toLocaleDateString('zh-CN', formatOptions)}`; } export function getDaysRemaining(endDate: string): number { const today = new Date(getTodayInTokyo()); const end = new Date(endDate); return Math.ceil((end.getTime() - today.getTime()) / (1000 * 60 * 60 * 24)); } export function isKRActive(kr: KR): boolean { const today = getTodayInTokyo(); return kr.period_start <= today && kr.period_end >= today; }