import path from 'node:path'

import { PROJECT_ROOT } from '../../config/runtime.js'
import { readJsonFile, writeJsonFile } from '../../utils/json-file-store.js'

const SCHEDULED_JOBS_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'scheduled-jobs.json')
const CLOUDTENTACLES_HEALTH_JOB_ID = 'cloudtentacles-health'

type JsonObject = Record<string, any>

export function getScheduledJobsFilePath() {
  return SCHEDULED_JOBS_FILE_PATH
}

export function getScheduledJobsConfig() {
  return loadScheduledJobsConfigFromFile()
}

export function saveScheduledJobsConfig(rawValue: unknown) {
  return writeJsonFile(SCHEDULED_JOBS_FILE_PATH, rawValue, normalizeScheduledJobsConfig)
}

export function getCloudtentaclesHealthJob(config: JsonObject = getScheduledJobsConfig()) {
  return (Array.isArray(config.jobs) ? config.jobs : [])
    .find((item) => String(item.id || '').trim() === CLOUDTENTACLES_HEALTH_JOB_ID)
    || createDefaultCloudtentaclesHealthJob()
}

function loadScheduledJobsConfigFromFile() {
  return readJsonFile(
    SCHEDULED_JOBS_FILE_PATH,
    createDefaultScheduledJobsConfig,
    normalizeScheduledJobsConfig,
  )
}

function normalizeScheduledJobsConfig(rawValue: unknown) {
  const source = isPlainObject(rawValue) ? rawValue : {}
  const rawJobs = Array.isArray(source.jobs) ? source.jobs : []
  const jobs = rawJobs.map((item) => normalizeScheduledJob(item)).filter(Boolean)
  const hasCloudtentaclesHealth = jobs.some((item) => item.id === CLOUDTENTACLES_HEALTH_JOB_ID)

  if (!hasCloudtentaclesHealth) {
    jobs.push(createDefaultCloudtentaclesHealthJob())
  }

  return {
    enabled: typeof source.enabled === 'boolean' ? source.enabled : true,
    jobs,
  }
}

function normalizeScheduledJob(rawValue: unknown) {
  if (!isPlainObject(rawValue)) {
    return null
  }

  const type = String(rawValue.type || '').trim()
  if (type !== 'cloudtentacles_health') {
    return null
  }

  return normalizeCloudtentaclesHealthJob(rawValue)
}

function normalizeCloudtentaclesHealthJob(rawValue: JsonObject) {
  const config = isPlainObject(rawValue.config) ? rawValue.config : {}

  return {
    id: CLOUDTENTACLES_HEALTH_JOB_ID,
    type: 'cloudtentacles_health',
    enabled: rawValue.enabled === true,
    intervalSeconds: normalizeRangeInteger(rawValue.intervalSeconds, 300, 60, 86400),
    cooldownSeconds: normalizeRangeInteger(rawValue.cooldownSeconds, 1800, 60, 86400),
    config: {
      assetThreshold: normalizeRangeInteger(config.assetThreshold, 500, 0, 999999),
    },
  }
}

function createDefaultScheduledJobsConfig() {
  return {
    enabled: true,
    jobs: [
      createDefaultCloudtentaclesHealthJob(),
    ],
  }
}

function createDefaultCloudtentaclesHealthJob() {
  return {
    id: CLOUDTENTACLES_HEALTH_JOB_ID,
    type: 'cloudtentacles_health',
    enabled: false,
    intervalSeconds: 300,
    cooldownSeconds: 1800,
    config: {
      assetThreshold: 500,
    },
  }
}

function normalizeRangeInteger(value: unknown, fallback: number, min: number, max: number) {
  const parsed = Number(value)
  if (!Number.isInteger(parsed)) {
    return fallback
  }

  return Math.min(max, Math.max(min, parsed))
}

function isPlainObject(value: unknown): value is JsonObject {
  return Object.prototype.toString.call(value) === '[object Object]'
}
