import { AlertCircle, Hand, Play, Square } from 'lucide-react'
import { useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Input } from '@/components/ui/input'
import {
useTokenMaxingProviders,
useTokenMaxingStart,
useTokenMaxingStatus,
useTokenMaxingStop,
} from '@/hooks/use-token-maxing'
/** Start/Stop controls + window picker. Mirrors the Card+Button+Input pattern
* used by SetBudgetDialog and the cron-jobs create form.
*/
export function TokenMaxingControls() {
const { t } = useTranslation()
const { data: status } = useTokenMaxingStatus()
const { data: providers } = useTokenMaxingProviders()
const startMutation = useTokenMaxingStart()
const stopMutation = useTokenMaxingStop()
const running = status?.running ?? false
const enabled = providers?.enabled ?? false
// Default window: now → now + 5h (matches the ZAI 5h reset window in the
// example config). The user can edit either field before starting.
const defaultStart = useMemo(() => toLocalInput(new Date()), [])
const defaultEnd = useMemo(() => {
const d = new Date()
d.setHours(d.getHours() + 5)
return toLocalInput(d)
}, [])
const [start, setStart] = useState(defaultStart)
const [end, setEnd] = useState(defaultEnd)
const handleStartWindow = () => {
const startIso = fromLocalInput(start)
const endIso = fromLocalInput(end)
if (!startIso || !endIso) return
if (new Date(endIso) <= new Date(startIso)) return
startMutation.mutate({ window: { start: startIso, end: endIso } })
}
const handleStartManual = () => {
startMutation.mutate({ manual: true })
}
const handleStop = () => {
stopMutation.mutate()
}
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-base">
<Play className="h-4 w-4" />
{t('tokenMaxing.controls.title')}
</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
{!enabled && (
<div className="flex items-start gap-2 rounded-md border border-warning-muted bg-warning-muted/30 p-3 text-sm">
<AlertCircle className="h-4 w-4 mt-0.5 text-warning shrink-0" />
<p className="text-warning">{t('tokenMaxing.controls.noEnabledProviders')}</p>
</div>
)}
<div className="grid gap-3 sm:grid-cols-2">
<div className="space-y-1">
<label className="text-xs text-muted-foreground">
{t('tokenMaxing.controls.windowStart')}
</label>
<Input
type="datetime-local"
value={start}
onChange={(e) => setStart(e.target.value)}
disabled={running}
/>
</div>
<div className="space-y-1">
<label className="text-xs text-muted-foreground">
{t('tokenMaxing.controls.windowEnd')}
</label>
<Input
type="datetime-local"
value={end}
onChange={(e) => setEnd(e.target.value)}
disabled={running}
/>
</div>
</div>
<div className="flex flex-wrap gap-2">
<Button
onClick={handleStartWindow}
disabled={running || !enabled || startMutation.isPending || !start || !end}
>
<Play className="h-4 w-4" />
{t('tokenMaxing.controls.startWindow')}
</Button>
<Button
variant="secondary"
onClick={handleStartManual}
disabled={running || !enabled || startMutation.isPending}
>
<Hand className="h-4 w-4" />
{t('tokenMaxing.controls.startManual')}
</Button>
<Button
variant="destructive"
onClick={handleStop}
disabled={!running || stopMutation.isPending}
>
<Square className="h-4 w-4" />
{t('tokenMaxing.controls.stop')}
</Button>
</div>
{startMutation.isError && (
<p className="text-sm text-error">
{t('tokenMaxing.controls.startFailed', {
error: (startMutation.error as Error | null)?.message ?? '',
})}
</p>
)}
{stopMutation.isError && (
<p className="text-sm text-error">
{t('tokenMaxing.controls.stopFailed', {
error: (stopMutation.error as Error | null)?.message ?? '',
})}
</p>
)}
</CardContent>
</Card>
)
}
/** Format a Date as the `YYYY-MM-DDTHH:mm` value that `<input type="datetime-local">` expects. */
function toLocalInput(d: Date): string {
const pad = (n: number) => String(n).padStart(2, '0')
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`
}
/** Convert `<input type="datetime-local">` value back to ISO-8601 UTC. */
function fromLocalInput(local: string): string | null {
if (!local) return null
const d = new Date(local)
if (Number.isNaN(d.getTime())) return null
return d.toISOString()
}