import { randomUUID } from "node:crypto"
import { appendEvent } from "../modules/events/service/events-service.js"
import type { CertificatesRenewRunSnapshot } from "../types/scheduler-run-snapshot.js"
import { SCHEDULER_RUN_SNAPSHOT_VERSION } from "../types/scheduler-run-snapshot.js"
import { mapRosCertificates } from "./certificate-parse.js"
import { runCertificateIssueJob } from "./certificate-issue-runner.js"
import {
  createIssueJobRecord,
  getCertificateRenewSettings,
  getServerRowByIdString,
  hasActiveIssueJob,
  listManagedCertificateTargets,
  touchCertificateRenewRunMeta,
} from "./certificates-service.js"
import { MikrotikClient } from "./mikrotik.js"

let collecting = false

export function getCertificateRenewCollectorState(): { running: boolean } {
  return { running: collecting }
}

export async function collectCertificatesRenewOnce(): Promise<CertificatesRenewRunSnapshot> {
  const sampledAt = new Date().toISOString()
  const settings = getCertificateRenewSettings()
  if (collecting) {
    return {
      v: SCHEDULER_RUN_SNAPSHOT_VERSION,
      job: "certificates_renew",
      sampledAt,
      skipped: true,
      checked: 0,
      renewed: 0,
      skippedTargets: 0,
      errors: [],
    }
  }

  collecting = true
  const started = Date.now()
  const snapshot: CertificatesRenewRunSnapshot = {
    v: SCHEDULER_RUN_SNAPSHOT_VERSION,
    job: "certificates_renew",
    sampledAt,
    checked: 0,
    renewed: 0,
    skippedTargets: 0,
    errors: [],
    targets: [],
  }

  try {
    if (!settings.enabled) {
      snapshot.skipped = true
      return snapshot
    }

    const targets = listManagedCertificateTargets()
    for (const target of targets) {
      snapshot.checked += 1
      const item = {
        serverId: target.serverId,
        certName: target.certName,
        action: "ok" as "ok" | "renewed" | "skipped" | "error",
        daysLeft: null as number | null,
        message: "",
      }

      if (hasActiveIssueJob(target.serverId, target.certName)) {
        item.action = "skipped"
        item.message = "Уже выполняется выпуск"
        snapshot.skippedTargets += 1
        snapshot.targets?.push(item)
        appendEvent({
          level: "info",
          eventType: "certificates.renew.skipped",
          sourceModule: "certificates",
          title: "Автообновление пропущено",
          message: `${target.certName}: уже выполняется выпуск`,
          entityType: "server",
          entityId: target.serverId,
        })
        continue
      }

      const server = getServerRowByIdString(target.serverId)
      if (!server) {
        item.action = "error"
        item.message = "Сервер не найден"
        snapshot.errors.push(`${target.certName}: сервер не найден`)
        snapshot.targets?.push(item)
        continue
      }

      try {
        const client = MikrotikClient.fromServer(server)
        const rows = await client.getCertificates()
        const mapped = mapRosCertificates(server.id, server.name, rows)
        const hit = mapped.find((c) => c.name === target.certName)
        if (!hit) {
          item.action = "error"
          item.message = "Сертификат не найден на устройстве"
          snapshot.errors.push(`${target.certName}: не найден на ${server.name}`)
          snapshot.targets?.push(item)
          continue
        }

        item.daysLeft = hit.daysLeft
        if (hit.daysLeft > settings.renewBeforeDays) {
          item.action = "ok"
          item.message = `До истечения ${hit.daysLeft} дн.`
          snapshot.targets?.push(item)
          continue
        }

        const jobId = randomUUID()
        createIssueJobRecord({
          id: jobId,
          serverId: target.serverId,
          certName: target.certName,
          domainNames: target.domainNames,
          keyType: target.keyType,
          trustStore: target.trustStore,
          source: "scheduler",
        })
        await runCertificateIssueJob(jobId)
        snapshot.renewed += 1
        item.action = "renewed"
        item.message = "Запущено обновление"
        snapshot.targets?.push(item)
      } catch (e) {
        const message = e instanceof Error ? e.message : String(e)
        item.action = "error"
        item.message = message
        snapshot.errors.push(`${target.certName}: ${message}`)
        snapshot.targets?.push(item)
      }
    }

    touchCertificateRenewRunMeta({
      lastCollectedAt: sampledAt,
      lastDurationMs: Date.now() - started,
      lastError: snapshot.errors.length > 0 ? snapshot.errors.join("; ") : null,
    })
    return snapshot
  } catch (e) {
    const message = e instanceof Error ? e.message : String(e)
    snapshot.fatalError = message
    touchCertificateRenewRunMeta({
      lastCollectedAt: sampledAt,
      lastDurationMs: Date.now() - started,
      lastError: message,
    })
    return snapshot
  } finally {
    collecting = false
  }
}
