import React, { useState, useCallback, useRef, useEffect } from 'react'; import { useLocalStorage } from '../hooks/useLocalStorage'; import { runHealthCheck, isAIConfigured } from '../services/geminiService'; import type { View, HealthCheckResult, BonsaiTree, DiaryLog } from '../types'; import { AppStatus, LogTag } from '../types'; import { StethoscopeIcon, LeafIcon, DropletIcon, BugIcon, BonsaiIcon, SparklesIcon, AlertTriangleIcon, UploadCloudIcon, CheckCircleIcon, ArrowLeftIcon } from '../components/icons'; import Spinner from '../components/Spinner'; type Stage = 'selecting_problem' | 'uploading_photo' | 'analyzing' | 'results'; const problemCategories = [ { name: 'Leaf Discoloration', description: 'Yellowing, browning, or strange colors on leaves.', icon: LeafIcon, instruction: "Take a clear, well-lit photo of the discolored leaves. Show both the top and underside if possible." }, { name: 'Spots or Residue', description: 'Powdery mildew, black spots, or sticky residue.', icon: DropletIcon, instruction: "Get a close-up of the spots or residue. Try to have a healthy leaf in the background for comparison." }, { name: 'Pests or Damage', description: 'Visible insects, webbing, or chewed leaves.', icon: BugIcon, instruction: "Photograph the pests or the damage they've caused. If the pest is tiny, get as close as you can while maintaining focus." }, { name: 'Wilting or Drooping', description: 'Leaves or branches are losing turgidity and hanging down.', icon: BonsaiIcon, instruction: "Show the entire wilting branch or section of the tree. Also, include a photo of the soil surface if possible." }, { name: 'General Weakness', description: 'Overall lack of vigor, poor growth, or branch dieback.', icon: AlertTriangleIcon, instruction: "Take a photo of the entire tree so its overall structure and condition are visible." }, ]; const HealthCheckView: React.FC<{ setActiveView: (view: View) => void }> = ({ setActiveView }) => { const [stage, setStage] = useState('selecting_problem'); const [selectedCategory, setSelectedCategory] = useState<(typeof problemCategories)[0] | null>(null); const [trees, setTrees] = useLocalStorage('bonsai-diary-trees', []); const [selectedTreeId, setSelectedTreeId] = useState(''); const [treeInfo, setTreeInfo] = useState({ species: '', location: '' }); const [image, setImage] = useState<{ preview: string; base64: string } | null>(null); const [result, setResult] = useState(null); const [error, setError] = useState(''); const fileInputRef = useRef(null); const aiConfigured = isAIConfigured(); useEffect(() => { if (selectedTreeId) { const tree = trees.find(t => t.id === selectedTreeId); if (tree) { setTreeInfo({ species: tree.species, location: tree.location }); } } else { setTreeInfo({ species: '', location: '' }); } }, [selectedTreeId, trees]); const handleSelectCategory = (category: (typeof problemCategories)[0]) => { setSelectedCategory(category); setStage('uploading_photo'); }; const handleFileChange = (event: React.ChangeEvent) => { const file = event.target.files?.[0]; if (file) { if (file.size > 4 * 1024 * 1024) { // 4MB limit setError("File size exceeds 4MB. Please upload a smaller image."); return; } const reader = new FileReader(); reader.onloadend = () => { const base64String = (reader.result as string).split(',')[1]; setImage({ preview: reader.result as string, base64: base64String }); setError(''); }; reader.onerror = () => setError("Failed to read the file."); reader.readAsDataURL(file); } }; const handleRunAnalysis = async () => { if (!image || !treeInfo.species || !treeInfo.location || !selectedCategory) { setError("Please provide all required information: an image, species, and location."); return; } setStage('analyzing'); setError(''); try { const analysisResult = await runHealthCheck(image.base64, treeInfo.species, treeInfo.location, selectedCategory.name); if(analysisResult) { setResult(analysisResult); setStage('results'); } else { throw new Error("Failed to get a diagnosis from the AI. It might be busy, or the image could not be processed. Please try again."); } } catch (e: any) { setError(e.message); setStage('uploading_photo'); } }; const handleSaveToLog = () => { if (!selectedTreeId || !result) { alert("No tree selected or no result to save."); return; }; const newLog: DiaryLog = { id: `log-${Date.now()}`, date: new Date().toISOString(), title: `Health Check: ${result.probableCause}`, notes: `Ran a diagnostic for "${selectedCategory?.name}". The AI diagnosed the issue with ${result.confidence} confidence.`, photos: image ? [image.base64] : [], tags: [LogTag.HealthDiagnosis], healthCheckResult: result }; const treeToUpdate = trees.find(t => t.id === selectedTreeId); if (treeToUpdate) { const updatedLogs = [newLog, ...treeToUpdate.logs].sort((a,b) => new Date(b.date).getTime() - new Date(a.date).getTime()); const updatedTree = { ...treeToUpdate, logs: updatedLogs }; const newTreeList = trees.map(t => t.id === selectedTreeId ? updatedTree : t); const storageKey = `yuki-app-bonsai-diary-trees`; window.localStorage.setItem(storageKey, JSON.stringify(newTreeList)); alert("Diagnosis saved to your tree's log!"); setActiveView('garden'); } }; const reset = () => { setStage('selecting_problem'); setSelectedCategory(null); setImage(null); setResult(null); setError(''); // Keep tree selection }; const renderHeader = () => (

Bonsai Health Check-up

Get a quick, focused diagnosis for a specific problem with your bonsai.

); const renderContent = () => { switch(stage) { case 'selecting_problem': return (

What seems to be the problem?

Select a category to begin the diagnosis.

{problemCategories.map(cat => { const Icon = cat.icon; return (
handleSelectCategory(cat)} className="bg-stone-50 rounded-lg p-6 border-2 border-transparent hover:border-green-600 hover:bg-white cursor-pointer transition-all duration-200 text-center flex flex-col items-center shadow-sm hover:shadow-xl">

{cat.name}

{cat.description}

)})}
); case 'uploading_photo': return (

{selectedCategory?.name}

Photo Instructions: {selectedCategory?.instruction}

fileInputRef.current?.click()} className="mt-2 flex justify-center rounded-lg border-2 border-dashed border-stone-300 px-6 py-10 hover:border-green-600 transition-colors cursor-pointer">
{image ? Bonsai preview : ( <>

Upload a file or drag and drop

PNG, JPG up to 4MB

)}
{selectedTreeId === 'new' && (
setTreeInfo(t => ({...t, species: e.target.value}))} className="w-full p-2 border rounded-md"/> setTreeInfo(t => ({...t, location: e.target.value}))} className="w-full p-2 border rounded-md"/>
)}
{error &&

{error}

} {!aiConfigured && (

AI features are disabled. Please set your Gemini API key in the{' '} .

)}
); case 'analyzing': return ; case 'results': if (!result) return null; const confidenceColor = result.confidence === 'High' ? 'bg-red-100 text-red-800' : result.confidence === 'Medium' ? 'bg-yellow-100 text-yellow-800' : 'bg-green-100 text-green-800'; return (

Diagnosis Complete

{result.probableCause}

{result.confidence} Confidence

{result.explanation}

Treatment Plan

    {result.treatmentPlan.map(step => (
  1. {step.step}

    {step.action}

    {step.details}

  2. ))}

Organic Alternatives

{result.organicAlternatives}

Future Prevention

{result.preventativeMeasures}

{selectedTreeId && selectedTreeId !== 'new' && ( )}
); } } return (
{renderHeader()}
{renderContent()}
); }; export default HealthCheckView;