"use client"; import { useState } from "react"; import { Button } from "@/components/ui/button"; import type { ScenarioInputPayload } from "@/lib/api"; const LOCATION_OPTIONS = [ { value: "RJ", label: "Rajasthan (High Solar)" }, { value: "GJ", label: "Gujarat (High Solar)" }, { value: "AP", label: "Andhra Pradesh" }, { value: "TN", label: "Tamil Nadu" }, { value: "MP", label: "Madhya Pradesh" }, { value: "KA", label: "Karnataka" }, ]; const STEP_LABELS = [ "Project Info", "Solar", "Wind", "BESS", "Solver", "Review", ]; interface WizardState { name: string; cod_date: string; // Solar solar_enabled: boolean; solar_location: string; solar_ac_mw: number; solar_dc_ac_ratio: number; solar_dc_mwp: number; // Wind wind_enabled: boolean; wind_location: string; wind_mw: number; // BESS bess_enabled: boolean; bess_mwh: number; bess_mw: number; // Solver solver_mode: "solve_tariff" | "fixed_tariff"; target_irr: number; fixed_tariff: number; } const DEFAULT_STATE: WizardState = { name: "", cod_date: "2027-04-01", solar_enabled: true, solar_location: "RJ", solar_ac_mw: 100, solar_dc_ac_ratio: 1.4, solar_dc_mwp: 140, wind_enabled: false, wind_location: "RJ", wind_mw: 50, bess_enabled: false, bess_mwh: 200, bess_mw: 50, solver_mode: "solve_tariff", target_irr: 0.18, fixed_tariff: 3.5, }; function Field({ label, children, }: { label: string; children: React.ReactNode; }) { return (
{children}
); } function Input({ value, onChange, type = "text", step, min, max, readOnly, className = "", }: { value: string | number; onChange: (v: string) => void; type?: string; step?: number; min?: number; max?: number; readOnly?: boolean; className?: string; }) { return ( onChange(e.target.value)} className={`border rounded px-3 py-1.5 text-sm focus:outline-none focus:ring-2 focus:ring-primary bg-background ${readOnly ? "bg-muted cursor-default" : ""} ${className}`} /> ); } function Select({ value, onChange, options, }: { value: string; onChange: (v: string) => void; options: { value: string; label: string }[]; }) { return ( ); } function Toggle({ label, checked, onChange, }: { label: string; checked: boolean; onChange: (v: boolean) => void; }) { return ( ); } // --------------------------------------------------------------------------- // Step components // --------------------------------------------------------------------------- function StepProjectInfo({ state, set, }: { state: WizardState; set: (k: keyof WizardState, v: WizardState[keyof WizardState]) => void; }) { return (

Project Information

set("name", v)} /> set("cod_date", v)} />
); } function StepSolar({ state, set, }: { state: WizardState; set: (k: keyof WizardState, v: WizardState[keyof WizardState]) => void; }) { return (

Solar Generation

set("solar_enabled", v)} /> {state.solar_enabled && ( <> set("solar_ac_mw", Number(v))} /> { const ratio = Number(v); set("solar_dc_ac_ratio", ratio); set("solar_dc_mwp", parseFloat((state.solar_ac_mw * ratio).toFixed(3))); }} /> {}} /> )}
); } function StepWind({ state, set, }: { state: WizardState; set: (k: keyof WizardState, v: WizardState[keyof WizardState]) => void; }) { return (

Wind Generation

set("wind_enabled", v)} /> {state.wind_enabled && ( <> set("wind_mw", Number(v))} /> )}
); } function StepBess({ state, set, }: { state: WizardState; set: (k: keyof WizardState, v: WizardState[keyof WizardState]) => void; }) { return (

BESS (Battery Storage)

set("bess_enabled", v)} /> {state.bess_enabled && ( <> set("bess_mwh", Number(v))} /> set("bess_mw", Number(v))} /> )}
); } function StepSolver({ state, set, }: { state: WizardState; set: (k: keyof WizardState, v: WizardState[keyof WizardState]) => void; }) { return (

Solver & Tariff

set("target_irr", Number(v))} /> ) : ( set("fixed_tariff", Number(v))} /> )}
); } function StepReview({ state }: { state: WizardState }) { return (

Review & Submit

Name
{state.name || "—"}
COD
{state.cod_date}
{state.solar_enabled && ( <>
Solar
{state.solar_ac_mw} MW AC / {state.solar_dc_mwp} MWp DC ({state.solar_location}, {state.solar_dc_ac_ratio}x)
)} {state.wind_enabled && ( <>
Wind
{state.wind_mw} MW ({state.wind_location})
)} {state.bess_enabled && ( <>
BESS
{state.bess_mwh} MWh / {state.bess_mw} MW
)}
Solver
{state.solver_mode === "solve_tariff" ? `Solve tariff @ IRR ${(state.target_irr * 100).toFixed(0)}%` : `Fixed ₹${state.fixed_tariff}/kWh`}
); } // --------------------------------------------------------------------------- // Main wizard // --------------------------------------------------------------------------- interface ScenarioWizardProps { onSubmit: (name: string, inputs: ScenarioInputPayload) => Promise; onCancel: () => void; } export function ScenarioWizard({ onSubmit, onCancel }: ScenarioWizardProps) { const [step, setStep] = useState(0); const [state, setState] = useState(DEFAULT_STATE); const [submitting, setSubmitting] = useState(false); const [error, setError] = useState(null); function set(k: K, v: WizardState[K]) { setState((prev) => ({ ...prev, [k]: v })); } const steps = [ , , , , , , ]; function buildInputs(): ScenarioInputPayload { return { project: { name: state.name, capacity_solar_mwp: state.solar_enabled ? state.solar_dc_mwp : 0, capacity_wind_mw: state.wind_enabled ? state.wind_mw : 0, capacity_bess_mwh: state.bess_enabled ? state.bess_mwh : 0, capacity_bess_mw: state.bess_enabled ? state.bess_mw : 0, cod_date: state.cod_date, }, solar: state.solar_enabled ? { location_id: state.solar_location, capacity_ac_mw: state.solar_ac_mw, dc_ac_ratio: state.solar_dc_ac_ratio, capacity_dc_mwp: state.solar_dc_mwp, } : null, wind: state.wind_enabled ? { location_id: state.wind_location, capacity_mw: state.wind_mw } : null, solver: state.solver_mode === "fixed_tariff" ? { mode: "fixed_tariff", fixed_tariff: state.fixed_tariff, } : { mode: "solve_tariff", target_equity_irr: state.target_irr, }, }; } async function handleSubmit() { if (!state.name.trim()) { setError("Please enter a scenario name."); return; } setSubmitting(true); setError(null); try { await onSubmit(state.name, buildInputs()); } catch (e) { setError(e instanceof Error ? e.message : "Unknown error"); setSubmitting(false); } } const isLast = step === steps.length - 1; return (
{/* Progress bar */}
{STEP_LABELS.map((label, i) => (
{label}
))}
{/* Step content */}
{steps[step]}
{error && (

{error}

)} {/* Navigation */}
{step > 0 && ( )}
{isLast ? ( ) : ( )}
); }