import axios, { type AxiosInstance } from 'axios'

import type { FullStatusResponse } from '../types/fullStatus'
import type {
  SiteConfigurationResponse,
  SitePvForecastCalibrationRow,
} from '../types/siteConfiguration'
import type { Notification } from '../types/dashboard'
import type { CurrentPlanResponse, PlanningCompareResponse, 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<unknown> {
  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<HealthDetailedResponse> {
  const { data } = await client.get<HealthDetailedResponse>('/health/detailed')
  return data
}

/** Aktivní lokality pro výběr v UI (`GET /me/sites`). */
export type MeSiteRow = {
  id: number
  code: string
  name: string
  timezone: string
  latitude?: number | string | null
  longitude?: number | string | null
  active: boolean
  notes?: string | null
  created_at?: string
}

export async function getMySites(): Promise<MeSiteRow[]> {
  const { data } = await client.get<MeSiteRow[]>('/me/sites')
  return Array.isArray(data) ? data : []
}

export async function getSiteStatusFull(siteId: number): Promise<FullStatusResponse> {
  const { data } = await client.get<FullStatusResponse>(`/sites/${siteId}/status/full`)
  return data
}

export async function getSiteConfiguration(siteId: number): Promise<SiteConfigurationResponse> {
  const { data } = await client.get<SiteConfigurationResponse>(`/sites/${siteId}/configuration`)
  return data
}

/** PATCH /sites/{id}/configuration/pv-forecast-calibration — pouze uvedená pole. */
export type PvForecastCalibrationPatchPayload = {
  delta_learn_min_ts?: string
  pv_curtailment_policy_effective_from?: string | null
  top_n_days?: number | null
  non_top_day_factor?: number | null
  day_weight_gamma?: number | null
  half_life_days?: number | null
  threshold_w?: number | null
}

export async function patchPvForecastCalibration(
  siteId: number,
  payload: PvForecastCalibrationPatchPayload,
): Promise<SitePvForecastCalibrationRow> {
  const { data } = await client.patch<SitePvForecastCalibrationRow>(
    `/sites/${siteId}/configuration/pv-forecast-calibration`,
    payload,
  )
  return data as SitePvForecastCalibrationRow
}

export type SiteNotificationsResponse = {
  notifications: Notification[]
}

export async function getSiteNotifications(siteId: number): Promise<SiteNotificationsResponse> {
  const { data } = await client.get<SiteNotificationsResponse>(`/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<SetSiteModeResponse> {
  const { data } = await client.post<SetSiteModeResponse>(`/sites/${siteId}/mode`, payload)
  return data
}

export async function getCurrentPlan(siteId: number): Promise<CurrentPlanResponse> {
  const { data } = await client.get<CurrentPlanResponse>(`/sites/${siteId}/plan/current`, {
    timeout: 60_000,
  })
  return data
}

export async function getPlanCompare(siteId: number): Promise<PlanningCompareResponse> {
  const { data } = await client.get<PlanningCompareResponse>(`/sites/${siteId}/plan/compare`, {
    timeout: 60_000,
  })
  return data
}

/** Řada FVE předpovědi (součet polí) po 15 min — doplnění grafu za horizont uloženého plánu. */
export type ForecastPvSlotRow = {
  interval_start: string
  pv_forecast_total_w?: number | null
}

export async function getForecastPvSlotsRange(
  siteId: number,
  fromIso: string,
  toIso: string,
): Promise<ForecastPvSlotRow[]> {
  const { data } = await client.get<{ slots?: ForecastPvSlotRow[] }>(
    `/sites/${siteId}/forecast/pv-slots`,
    { params: { from: fromIso, to: toIso }, timeout: 45_000 },
  )
  return Array.isArray(data?.slots) ? data.slots : []
}

/** Řádek z GET /sites/{id}/forecast/pv-slots-corrected — backend může doplnit další pole. */
export type ForecastPvSlotCorrectedRow = {
  interval_start: string
  pv_forecast_total_w?: number | null
  pv_forecast_corrected_w?: number | null
  slot_of_day?: number | null
}

/** Jedna položka slot profilu z `ems.fn_pv_forecast_delta_profile` (JSON). */
export type PvDeltaProfileSlotEntry = {
  slot_of_day: number
  delta_w: number
  sample_count: number
}

/** Volitelný JSON profilu delty (ladění / budoucí UI); `deltas` = součet přes pole, `deltas_by_array` = per pole. */
export type PvForecastDeltaProfileJson = {
  site_id?: number
  data_from?: string
  data_to?: string
  delta_learn_min_ts?: string
  half_life_days?: number
  threshold_w?: number
  top_n_days?: number | null
  deltas?: PvDeltaProfileSlotEntry[]
  deltas_by_array?: Record<string, { deltas: PvDeltaProfileSlotEntry[] }>
}

export type ForecastPvSlotsCorrectedParams = {
  delta_from?: string
  delta_to?: string
  half_life_days?: number
  threshold_w?: number
}

export async function getForecastPvSlotsRangeCorrected(
  siteId: number,
  fromIso: string,
  toIso: string,
  params?: ForecastPvSlotsCorrectedParams,
): Promise<ForecastPvSlotCorrectedRow[]> {
  const { data } = await client.get<{ slots?: ForecastPvSlotCorrectedRow[] }>(
    `/sites/${siteId}/forecast/pv-slots-corrected`,
    { params: { from: fromIso, to: toIso, ...params }, timeout: 45_000 },
  )
  return Array.isArray(data?.slots) ? data.slots : []
}

export type PvDeltaProfileQueryParams = {
  half_life_days?: number
  threshold_w?: number
  top_n_days?: number | null
  non_top_day_factor?: number | null
  day_weight_gamma?: number | null
}

/** GET /sites/{id}/forecast/pv-delta-profile — přímo JSON z `ems.fn_pv_forecast_delta_profile`. */
export async function getPvForecastDeltaProfile(
  siteId: number,
  fromIso: string,
  toIso: string,
  params?: PvDeltaProfileQueryParams,
): Promise<PvForecastDeltaProfileJson> {
  const { data } = await client.get<PvForecastDeltaProfileJson>(
    `/sites/${siteId}/forecast/pv-delta-profile`,
    { params: { from: fromIso, to: toIso, ...params }, timeout: 45_000 },
  )
  return data != null && typeof data === 'object' ? data : {}
}

export type Telemetry15mRow = {
  slot_start: string
  site_id: number
  avg_pv_w?: number | null
  avg_load_w?: number | null
  avg_grid_w?: number | null
  avg_battery_w?: number | null
  last_soc_pct?: number | null
  sample_count?: number | null
}

export async function getTelemetry15mRange(
  siteId: number,
  fromIso: string,
  toIso: string,
): Promise<Telemetry15mRow[]> {
  const { data } = await client.get<{ slots?: Telemetry15mRow[] }>(`/sites/${siteId}/timeseries/telemetry-15m`, {
    params: { from: fromIso, to: toIso },
    timeout: 60_000,
  })
  return Array.isArray(data?.slots) ? data.slots : []
}

export type BaselineLoadSlotRow = {
  interval_start: string
  forecast_w: number
  confidence_w?: number
}

export async function getBaselineLoadSlotsRange(
  siteId: number,
  fromIso: string,
  toIso: string,
): Promise<BaselineLoadSlotRow[]> {
  const { data } = await client.get<{ slots?: BaselineLoadSlotRow[] }>(
    `/sites/${siteId}/forecast/load-baseline-slots`,
    { params: { from: fromIso, to: toIso }, timeout: 60_000 },
  )
  return Array.isArray(data?.slots) ? data.slots : []
}

/** 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<SiteEffectivePriceRowDto[]> {
  const { data } = await client.get<SiteEffectivePriceRowDto[]>(`/sites/${siteId}/prices`, {
    params: { date },
    timeout: 60_000,
  })
  return Array.isArray(data) ? data : []
}

export async function getSitePricesSlotsRange(
  siteId: number,
  fromIso: string,
  toIso: string,
): Promise<SiteEffectivePriceRowDto[]> {
  const { data } = await client.get<{ slots?: SiteEffectivePriceRowDto[] }>(
    `/sites/${siteId}/prices/slots`,
    { params: { from: fromIso, to: toIso }, timeout: 60_000 },
  )
  return Array.isArray(data?.slots) ? data.slots : []
}

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<ForecastPvDayResponse> {
  const { data } = await client.get<ForecastPvDayResponse>(`/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<NegativePredictionsResponseDto> {
  const { data } = await client.get<NegativePredictionsResponseDto>(
    `/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<RunPlanResponse> {
  const { data } = await client.post<RunPlanResponse>(
    `/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<PricesImportResponse> {
  const { data } = await client.post<PricesImportResponse>(
    `/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<ForecastRunResponse> {
  const { data } = await client.post<ForecastRunResponse>(
    `/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<ActiveEvSessionRow[]> {
  const { data } = await client.get<ActiveEvSessionRow[]>(
    `/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<PatchEvSessionResponse> {
  const { data } = await client.patch<PatchEvSessionResponse>(
    `/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
  reg178_control_board_special_1: number
  reg178_mi_export_cutoff_bits: number
  reg178_mi_export_cutoff_is_on: boolean
  reg191_peak_shaving_w: number
  read_at: string
}

export async function getDeyeRegisters(siteId: number): Promise<DeyeRegistersLive> {
  const { data } = await client.get<DeyeRegistersLive>(`/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<ModbusJournalResponse> {
  const { data } = await client.get<ModbusJournalResponse>(
    `/sites/${siteId}/control/journal`,
    { params: { limit }, timeout: 15_000 },
  )
  return {
    commands: Array.isArray(data?.commands) ? data.commands : [],
  }
}

export { client as backendClient }
