import axios, { type AxiosInstance } from 'axios' import type { FullStatusResponse } from '../types/fullStatus' import type { Notification } from '../types/dashboard' import type { CurrentPlanResponse, RunPlanResponse } from '../types/plan' const client: AxiosInstance = axios.create({ baseURL: '/api/v1', headers: { Accept: 'application/json' }, timeout: 30_000, }) /** Příklad: health / readiness až budou v FastAPI exponované. */ export async function getBackendHealth(): Promise { const { data } = await client.get('/health') return data } export type HealthDetailedResponse = { db: 'ok' | 'error' scheduler: 'running' | 'stopped' telemetry_loop: 'running' | 'stopped' last_telemetry_age_sec: number last_plan_age_sec: number active_jobs: { id: string; next_run_time: string | null }[] } export async function getBackendHealthDetailed(): Promise { const { data } = await client.get('/health/detailed') return data } export async function getSiteStatusFull(siteId: number): Promise { const { data } = await client.get(`/sites/${siteId}/status/full`) return data } export type SiteNotificationsResponse = { notifications: Notification[] } export async function getSiteNotifications(siteId: number): Promise { const { data } = await client.get(`/sites/${siteId}/notifications`, { timeout: 30_000, }) return { notifications: Array.isArray(data?.notifications) ? data.notifications : [], } } export type SetSiteModePayload = { mode: string notes: string | null valid_until: string | null } export type SetSiteModeResponse = { success: boolean mode: string activated_at: string } export async function postSiteMode( siteId: number, payload: SetSiteModePayload, ): Promise { const { data } = await client.post(`/sites/${siteId}/mode`, payload) return data } export async function getCurrentPlan(siteId: number): Promise { const { data } = await client.get(`/sites/${siteId}/plan/current`, { timeout: 60_000, }) return data } /** GET /api/v1/sites/{id}/prices?date=YYYY-MM-DD */ export type SiteEffectivePriceRowDto = { site_id: number interval_start: string interval_end?: string effective_buy_price_czk_kwh?: number | string | null effective_sell_price_czk_kwh?: number | string | null } export async function getSitePrices(siteId: number, date: string): Promise { const { data } = await client.get(`/sites/${siteId}/prices`, { params: { date }, timeout: 60_000, }) return Array.isArray(data) ? data : [] } export type ForecastPvIntervalRow = { interval_start: string power_w?: number | string | null pv_array_id?: number } export type ForecastPvDayResponse = { pv_a: ForecastPvIntervalRow[] pv_b: ForecastPvIntervalRow[] } export async function getSiteForecastPv(siteId: number, date: string): Promise { const { data } = await client.get(`/sites/${siteId}/forecast/pv`, { params: { date }, timeout: 60_000, }) return { pv_a: Array.isArray(data?.pv_a) ? data.pv_a : [], pv_b: Array.isArray(data?.pv_b) ? data.pv_b : [], } } export type NegPricePredictionDto = { predicted_date: string window_start_hour: number window_end_hour: number probability_pct: number expected_min_price: number | null reason: string } export type NegativePredictionsResponseDto = { predictions: NegPricePredictionDto[] insufficient_history: boolean } export async function getNegativePricePredictions( siteId: number, ): Promise { const { data } = await client.get( `/sites/${siteId}/prices/negative-predictions`, { timeout: 30_000 }, ) return { predictions: Array.isArray(data?.predictions) ? data.predictions : [], insufficient_history: Boolean(data?.insufficient_history), } } export async function postRunPlan( siteId: number, planType: 'daily' | 'rolling', ): Promise { const { data } = await client.post( `/sites/${siteId}/plan/run`, null, { params: { type: planType }, timeout: 120_000 }, ) return data } export type PricesImportResponse = { slots_imported: number date: string first_price_czk_kwh: number } export async function postImportSitePrices( siteId: number, date?: string, ): Promise { const { data } = await client.post( `/sites/${siteId}/prices/import`, null, { params: date ? { date } : undefined, timeout: 60_000, }, ) return data } export type ForecastRunResponse = { intervals_saved: number pv_arrays: number } export async function postRunForecast(siteId: number): Promise { const { data } = await client.post( `/sites/${siteId}/forecast/run`, null, { timeout: 120_000 }, ) return data } /** Aktivní EV session (GET .../ev/sessions/active) – join vozidlo + nabíječka */ export type ActiveEvSessionRow = { id: number charger_id: number vehicle_id: number | null session_start: string energy_delivered_wh: number target_soc_pct: number | null target_deadline: string | null make: string | null model: string | null battery_capacity_kwh: number | null default_target_soc_pct: number | null default_deadline_hour: number | null charger_code: string charger_name: string | null } export async function getActiveEvSessions(siteId: number): Promise { const { data } = await client.get( `/sites/${siteId}/ev/sessions/active`, ) return data } export type PatchEvSessionPayload = { target_soc_pct: number | null target_deadline: string | null } export type PatchEvSessionResponse = { success: boolean session_id: number } export async function patchEvSession( siteId: number, sessionId: number, payload: PatchEvSessionPayload, ): Promise { const { data } = await client.patch( `/sites/${siteId}/ev/sessions/${sessionId}`, payload, ) return data } /** Živé hodnoty registrů Deye (GET …/control/registers). */ export type DeyeRegistersLive = { reg108_charge_a: number reg109_discharge_a: number reg141_energy_mode: number reg142_limit_control: number reg143_export_limit_w: number reg178_peak_shaving_switch: number reg191_peak_shaving_w: number read_at: string } export async function getDeyeRegisters(siteId: number): Promise { const { data } = await client.get(`/sites/${siteId}/control/registers`, { timeout: 15_000, }) return data } export type ModbusJournalCommandDto = { id: number register: number register_name: string | null value_to_write: number value_written: number | null value_verified: number | null status: string attempt_count: number created_at: string } export type ModbusJournalResponse = { commands: ModbusJournalCommandDto[] } export async function getCommandJournal( siteId: number, limit = 50, ): Promise { const { data } = await client.get( `/sites/${siteId}/control/journal`, { params: { limit }, timeout: 15_000 }, ) return { commands: Array.isArray(data?.commands) ? data.commands : [], } } export { client as backendClient }