//go:build windows

package client

import (
	"encoding/json"
	"strings"
)

const kevProbeScript = `
$ErrorActionPreference = 'SilentlyContinue'
$out = [ordered]@{}

# Exchange (ProxyLogon / ProxyLogon family)
$exSvc = @(Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Name -like 'MSExchange*' -or $_.DisplayName -like '*Exchange*' })
$exReg = Test-Path 'HKLM:\SOFTWARE\Microsoft\ExchangeServer'
$out.exchange_installed = ($exSvc.Count -gt 0 -or $exReg)

# Domain Controller (Zerologon surface)
try {
  $dc = (Get-CimInstance Win32_ComputerSystem).DomainRole -in 4,5
} catch { $dc = $false }
$out.is_domain_controller = $dc

# Pulse / Ivanti VPN client or service
$pulse = @(Get-Service -ErrorAction SilentlyContinue | Where-Object {
  $_.DisplayName -match 'Pulse|Ivanti|Juniper Pulse' -or $_.Name -match 'Pulse'
})
$out.pulse_present = ($pulse.Count -gt 0)

# Citrix ADC / Gateway / Workspace server components
$citrix = @(
  Test-Path 'C:\inetpub\scripts',
  (Test-Path 'C:\Program Files\Citrix'),
  (Test-Path 'C:\Program Files (x86)\Citrix')
) | Where-Object { $_ }
$out.citrix_present = ($citrix.Count -gt 0)

# F5 BIG-IP local management (rare on desktop)
$f5 = @(Get-Process -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'bigip|f5' })
$out.f5_process = ($f5.Count -gt 0)

# Confluence / Atlassian stack
$conf = @(Get-Process -ErrorAction SilentlyContinue | Where-Object {
  $_.Path -match 'atlassian|confluence|tomcat' -or $_.ProcessName -match 'confluence|tomcat'
})
$out.confluence_like = ($conf.Count -gt 0)

# ManageEngine ADSelfService Plus
$me = @(
  Test-Path 'C:\Program Files\ManageEngine',
  Test-Path 'C:\ManageEngine'
) | Where-Object { $_ }
$out.manageengine_present = ($me.Count -gt 0)

# Fortinet FortiClient
$forti = @(Get-Process -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'forti' })
$out.forticlient = ($forti.Count -gt 0)

# VMware vCenter / vSphere client heavy installs
$vmw = @(Get-Service -ErrorAction SilentlyContinue | Where-Object { $_.Name -match 'vpxd|VMware' })
$out.vmware_serverish = ($vmw.Count -gt 0)

# Print Spooler (PrintNightmare surface)
try {
  $sp = Get-Service Spooler
  $out.spooler_running = ($sp.Status -eq 'Running')
} catch { $out.spooler_running = $false }

# Log4j jars — shallow search (bounded)
$log4j = @()
$roots = @(
  $env:ProgramFiles,
  ${env:ProgramFiles(x86)},
  'C:\ProgramData'
) | Where-Object { $_ -and (Test-Path $_) }
foreach ($root in $roots) {
  $log4j += Get-ChildItem -Path $root -Filter 'log4j-core*.jar' -Recurse -Depth 3 -ErrorAction SilentlyContinue |
    Select-Object -First 5 -ExpandProperty FullName
}
$out.log4j_jars = @($log4j | Select-Object -Unique)

$out | ConvertTo-Json -Compress -Depth 4
`

type kevProbeResult struct {
	ExchangeInstalled   bool     `json:"exchange_installed"`
	IsDomainController  bool     `json:"is_domain_controller"`
	PulsePresent        bool     `json:"pulse_present"`
	CitrixPresent       bool     `json:"citrix_present"`
	F5Process           bool     `json:"f5_process"`
	ConfluenceLike      bool     `json:"confluence_like"`
	ManageEnginePresent bool     `json:"manageengine_present"`
	FortiClient         bool     `json:"forticlient"`
	VMwareServerish     bool     `json:"vmware_serverish"`
	SpoolerRunning      bool     `json:"spooler_running"`
	Log4jJars           []string `json:"log4j_jars"`
}

func runKEVProbe() (*kevProbeResult, error) {
	out, err := silentCombinedOutput(
		"powershell", "-NoProfile", "-ExecutionPolicy", "Bypass", "-WindowStyle", "Hidden", "-Command",
		kevProbeScript,
	)
	if err != nil {
		return nil, err
	}
	raw := strings.TrimSpace(string(out))
	if idx := strings.LastIndex(raw, "{"); idx > 0 {
		raw = raw[idx:]
	}
	var p kevProbeResult
	if err := json.Unmarshal([]byte(raw), &p); err != nil {
		return nil, err
	}
	return &p, nil
}

func scanKEVExposure(patch *PatchStatusReport, ports *ListenPortsReport, sec *SysCheckSecurity) *KEVScanReport {
	probe, probeErr := runKEVProbe()
	findings := make([]KEVFinding, 0, len(KEVCatalog))

	patchDays := -1
	if patch != nil && patch.LastPatchDays != nil {
		patchDays = *patch.LastPatchDays
	}
	listening := map[int]bool{}
	if ports != nil {
		for _, p := range ports.Ports {
			listening[p.Port] = true
		}
	}

	for _, e := range KEVCatalog {
		f := KEVFinding{
			CVE: e.ID, Name: e.Name, Product: e.Product, Severity: e.Severity, CISAKEV: e.CISAKEV,
			Status: "clear", Detail: e.Description,
		}
		if probeErr != nil {
			f.Status = "n/a"
			f.Detail = "probe unavailable"
			findings = append(findings, f)
			continue
		}

		switch e.ID {
		case "CVE-2021-26855", "CVE-2020-0688":
			if probe.ExchangeInstalled {
				f.Status = "exposed"
				f.Detail = "Microsoft Exchange services/registry detected — verify Mar 2021+ CU patches"
				if patchDays >= 0 && patchDays > 90 {
					f.Status = "likely"
					f.Detail += "; host patch age > 90 days"
				}
			}
		case "CVE-2020-1472":
			if probe.IsDomainController {
				f.Status = "likely"
				f.Detail = "Domain controller role — ensure Aug 2020 Netlogon patch (Zerologon) applied"
				if patchDays >= 0 && patchDays > 60 {
					f.Status = "exposed"
					f.Detail = "DC with patch age > 60 days — Zerologon mitigation urgency"
				}
			}
		case "CVE-2021-44228":
			if len(probe.Log4jJars) > 0 {
				f.Status = "likely"
				f.Detail = "log4j-core JAR(s) found: " + strings.Join(probe.Log4jJars, "; ")
			}
		case "CVE-2019-19781":
			if probe.CitrixPresent {
				f.Status = "likely"
				f.Detail = "Citrix install paths present — verify ADC/Gateway patch level if server role"
			}
		case "CVE-2019-11510":
			if probe.PulsePresent {
				f.Status = "likely"
				f.Detail = "Pulse/Ivanti VPN software detected — verify appliance firmware if VPN gateway"
			}
		case "CVE-2020-5902", "CVE-2022-1388":
			if probe.F5Process || listening[443] {
				if probe.F5Process {
					f.Status = "likely"
					f.Detail = "F5-related process detected"
				}
			}
		case "CVE-2021-26084", "CVE-2022-26134":
			if probe.ConfluenceLike {
				f.Status = "likely"
				f.Detail = "Atlassian/Confluence-like Java process — verify Confluence patch level"
			}
		case "CVE-2021-40539":
			if probe.ManageEnginePresent {
				f.Status = "likely"
				f.Detail = "ManageEngine directory present — verify ADSelfService Plus version"
			}
		case "CVE-2018-13379":
			if probe.FortiClient {
				f.Status = "likely"
				f.Detail = "Fortinet client process running — verify FortiOS/FortiClient versions on VPN edge"
			}
		case "CVE-2021-21972":
			if probe.VMwareServerish {
				f.Status = "likely"
				f.Detail = "VMware server-style services detected — verify vCenter patch level"
			}
		case "CVE-2021-34527":
			if probe.SpoolerRunning && !probe.IsDomainController {
				f.Status = "likely"
				f.Detail = "Print Spooler running — restrict if not required (PrintNightmare era)"
			}
		}

		// Stale patching amplifies any likely/exposed KEV surface
		if f.Status == "likely" && patchDays > 120 {
			f.Detail += " · OS patches older than 120 days"
		}

		findings = append(findings, f)
	}

	r := finalizeKEVReport(findings)
	if r.ExposedCount > 0 || r.CriticalCount > 0 {
		r.Summary = "CISA KEV-style exposure indicators detected — patch or isolate affected roles"
	} else if r.LikelyCount > 0 {
		r.Summary = "Some KEV-related software stacks detected — verify versions and patches"
	} else {
		r.Summary = "No high-confidence KEV exposure indicators on this host"
	}
	return r
}
