import { MODULES } from '../data/modules.js'
import { downloadService } from './download_service.js'
import { mkdir, statfs } from 'node:fs/promises'
import { hostname, uptime } from 'node:os'
import { config } from '../config.js'
import type { ArkaModule, ModuleStatus, NodeRuntime, TcpLayer } from '../types.js'

export interface LayerSummary {
  layer: TcpLayer
  online: number
  total: number
}

export interface NodeStatus {
  /** Bendra mazgo būklė. */
  status: 'operational' | 'degraded' | 'critical'
  modules: ArkaModule[]
  layers: LayerSummary[]
  /** Įdiegtų ir veikiančių modulių dalis procentais — atitinka TCP pasiruošimo metriką. */
  readiness: number
  /** Reali vietinio hosto telemetrija, apskaičiuota užklausos metu. */
  node: NodeRuntime
  summary: Record<ModuleStatus, number>
}

/**
 * Modulių / paslaugų būklės servisas. Turinį naudojantys moduliai (Žinių bazė, Žemėlapiai)
 * automatiškai persijungia į „online", kai atsisiunčiamas atitinkamas turinys.
 */
export class ServicesService {
  listModules(): ArkaModule[] {
    return MODULES
  }

  getModule(id: string): ArkaModule | undefined {
    return MODULES.find((m) => m.id === id)
  }

  /**
   * Grąžina modulius su perskaičiuota būsena: jei modulis priklauso nuo
   * turinio (`contentType`) ir tas turinys atsisiųstas — būsena „online";
   * priešingu atveju lieka bazinė. Originalūs duomenys nemutuojami.
   */
  private async resolveModules(): Promise<ArkaModule[]> {
    const resolved: ArkaModule[] = []
    for (const mod of MODULES) {
      if (mod.contentType) {
        const hasContent = await downloadService.hasDownloadedType(mod.contentType)
        resolved.push({ ...mod, status: hasContent ? 'online' : mod.status })
      } else {
        resolved.push(mod)
      }
    }
    return resolved
  }

  private layerSummary(modules: ArkaModule[]): LayerSummary[] {
    const layers: TcpLayer[] = ['perimeter', 'system', 'human']
    return layers.map((layer) => {
      const inLayer = modules.filter((m) => m.layer === layer)
      const online = inLayer.filter((m) => m.status === 'online').length
      return { layer, online, total: inLayer.length }
    })
  }

  private async runtime(): Promise<NodeRuntime> {
    await mkdir(config.storagePath, { recursive: true })
    const disk = await statfs(config.storagePath)
    const diskTotal = disk.blocks * disk.bsize
    const diskFree = disk.bavail * disk.bsize
    const processMemory = process.memoryUsage()
    const memoryTotal = processMemory.heapTotal
    const memoryFree = Math.max(0, processMemory.heapTotal - processMemory.heapUsed)
    const host = hostname()

    return {
      name: `ARKA-${host.split('.')[0].toUpperCase()}`,
      version: '0.2.0',
      hostname: host,
      mode: 'local-only',
      uptimeSeconds: Math.round(uptime()),
      processUptimeSeconds: Math.round(process.uptime()),
      memory: {
        totalBytes: memoryTotal,
        freeBytes: memoryFree,
        usedPercent: Math.round(((memoryTotal - memoryFree) / memoryTotal) * 100),
      },
      storage: {
        path: config.storagePath,
        totalBytes: diskTotal,
        freeBytes: diskFree,
        usedPercent: diskTotal > 0 ? Math.round(((diskTotal - diskFree) / diskTotal) * 100) : 0,
      },
      updatedAt: new Date().toISOString(),
    }
  }

  async getStatus(): Promise<NodeStatus> {
    const modules = await this.resolveModules()
    const installed = modules.filter((m) => m.status !== 'not_installed')
    const online = modules.filter((m) => m.status === 'online').length
    const readiness =
      installed.length === 0 ? 0 : Math.round((online / installed.length) * 100)

    const hasOffline = installed.some(
      (m) => m.status === 'offline' || m.status === 'degraded'
    )
    let status: NodeStatus['status'] = 'operational'
    if (readiness < 50) status = 'critical'
    else if (hasOffline) status = 'degraded'

    return {
      status,
      modules,
      layers: this.layerSummary(modules),
      readiness,
      node: await this.runtime(),
      summary: {
        online: modules.filter((m) => m.status === 'online').length,
        degraded: modules.filter((m) => m.status === 'degraded').length,
        offline: modules.filter((m) => m.status === 'offline').length,
        not_installed: modules.filter((m) => m.status === 'not_installed').length,
      },
    }
  }

  /** Pakeičia bazinę modulio būseną (MVP — atmintyje; nepersistuojama). */
  setStatus(id: string, status: ModuleStatus): ArkaModule | undefined {
    const mod = this.getModule(id)
    if (mod) mod.status = status
    return mod
  }
}

export const servicesService = new ServicesService()
