'use client'; import { useState, useCallback } from 'react'; import { useLocale } from './LocaleProvider'; import { ts } from '@/lib/i18n'; import { getMoonPhaseInfo, getMoonZodiacSign } from '@/lib/lunar'; type PhaseDescKey = | 'phase_desc_new' | 'phase_desc_waxing_crescent' | 'phase_desc_first_quarter' | 'phase_desc_waxing_gibbous' | 'phase_desc_full' | 'phase_desc_waning_gibbous' | 'phase_desc_last_quarter' | 'phase_desc_waning_crescent'; const PHASE_DESC_MAP: Record = { new_moon: 'phase_desc_new', waxing_crescent: 'phase_desc_waxing_crescent', first_quarter: 'phase_desc_first_quarter', waxing_gibbous: 'phase_desc_waxing_gibbous', full_moon: 'phase_desc_full', waning_gibbous: 'phase_desc_waning_gibbous', last_quarter: 'phase_desc_last_quarter', waning_crescent: 'phase_desc_waning_crescent', }; const ZODIAC_EMOJI: Record = { Aries: '♈', Taurus: '♉', Gemini: '♊', Cancer: '♋', Leo: '♌', Virgo: '♍', Libra: '♎', Scorpio: '♏', Sagittarius: '♐', Capricorn: '♑', Aquarius: '♒', Pisces: '♓', }; function MoonVisual({ phase, size = 160 }: { phase: number; size?: number }) { const drawMoon = useCallback((ctx: CanvasRenderingContext2D) => { const w = size; const h = size; const margin = 14; const r = w / 2 - margin; const cx = w / 2; const cy = h / 2; ctx.clearRect(0, 0, w, h); // Moon shadow (dark side) ctx.beginPath(); ctx.arc(cx, cy, r, 0, Math.PI * 2); ctx.fillStyle = '#1a1a2e'; ctx.fill(); // Lit surface ctx.beginPath(); const angleRad = phase * 2 * Math.PI; if (phase <= 0.5) { // Waxing: right side lit ctx.arc(cx, cy, r, -Math.PI / 2, Math.PI / 2, false); const sweep = Math.cos(angleRad); ctx.ellipse(cx, cy, Math.abs(sweep) * r, r, 0, Math.PI / 2, -Math.PI / 2, sweep < 0); } else { // Waning: left side lit ctx.arc(cx, cy, r, Math.PI / 2, -Math.PI / 2, false); const sweep = Math.cos(angleRad); ctx.ellipse(cx, cy, Math.abs(sweep) * r, r, 0, -Math.PI / 2, Math.PI / 2, sweep > 0); } ctx.closePath(); // Gradient for realistic look const grad = ctx.createRadialGradient(cx - r * 0.3, cy - r * 0.3, 0, cx, cy, r); grad.addColorStop(0, '#fef9c3'); grad.addColorStop(0.5, '#fbbf24'); grad.addColorStop(1, '#b45309'); ctx.fillStyle = grad; ctx.fill(); // Surface texture (craters) const craters = [ { x: 0.3, y: 0.35, r: 0.08 }, { x: 0.6, y: 0.25, r: 0.06 }, { x: 0.45, y: 0.6, r: 0.1 }, { x: 0.7, y: 0.55, r: 0.05 }, { x: 0.35, y: 0.75, r: 0.07 }, { x: 0.55, y: 0.45, r: 0.04 }, ]; craters.forEach(crater => { ctx.beginPath(); ctx.arc(cx + (crater.x - 0.5) * 2 * r, cy + (crater.y - 0.5) * 2 * r, crater.r * r, 0, Math.PI * 2); ctx.fillStyle = 'rgba(0, 0, 0, 0.1)'; ctx.fill(); }); // Glow ctx.beginPath(); ctx.arc(cx, cy, r + 8, 0, Math.PI * 2); const glowGrad = ctx.createRadialGradient(cx, cy, r - 2, cx, cy, r + 15); glowGrad.addColorStop(0, 'rgba(251, 191, 36, 0.15)'); glowGrad.addColorStop(1, 'rgba(251, 191, 36, 0)'); ctx.fillStyle = glowGrad; ctx.fill(); }, [phase, size]); const canvasRef = useCallback((node: HTMLCanvasElement | null) => { if (node) { const ctx = node.getContext('2d'); if (ctx) drawMoon(ctx); } }, [drawMoon]); return ( ); } export default function PhaseSimulator() { const { locale } = useLocale(); const [date, setDate] = useState(() => { const d = new Date(); return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; }); const selectedDate = new Date(date + 'T12:00:00'); const phaseInfo = getMoonPhaseInfo(selectedDate); const zodiac = getMoonZodiacSign(selectedDate); const phaseDescKey: PhaseDescKey = PHASE_DESC_MAP[phaseInfo.phaseName] || 'phase_desc_full'; return (

{ts('simulator_title', locale)}

{ts('simulator_subtitle', locale)}

{/* Moon visual */}
{/* Controls & info */}
setDate(e.target.value)} className="w-full px-4 py-3 rounded-xl bg-white/5 border border-white/10 text-white focus:border-indigo-400/50 focus:outline-none transition-all" />

{ts('current_phase', locale)}

{phaseInfo.emoji} {ts(phaseInfo.phaseName, locale)}

{ts('simulator_illumination', locale)}

{phaseInfo.illumination}%

{ts('simulator_age', locale)}

{phaseInfo.age.toFixed(1)} {ts('simulator_days', locale)}

{ts('simulator_zodiac', locale)}

{ZODIAC_EMOJI[zodiac] || '♈'} {zodiac}

{/* Phase description */}

{ts(phaseDescKey, locale)}

); }