$ErrorActionPreference = "Stop"

function Convert-KelvinTenthsToCelsius($value) {
  if ($null -eq $value -or $value -le 0) { return $null }
  return [math]::Round(($value / 10) - 273.15)
}

function New-SensorValue($label, $value, $unit, $source) {
  [pscustomobject]@{
    Label = $label
    Value = $value
    Unit = $unit
    Source = $source
    Display = if ($null -eq $value) { "센서 접근 제한" } else { "$value$unit" }
    DisplayEn = if ($null -eq $value) { "Sensor access limited" } else { "$value$unit" }
  }
}

function Get-LhmTemperature {
  $namespaces = @("root\LibreHardwareMonitor", "root\OpenHardwareMonitor")
  $readings = @()

  foreach ($namespace in $namespaces) {
    try {
      $sensors = Get-CimInstance -Namespace $namespace -ClassName Sensor -ErrorAction Stop |
        Where-Object { $_.SensorType -eq "Temperature" -and $null -ne $_.Value }

      foreach ($sensor in $sensors) {
        $readings += [pscustomobject]@{
          Name = "$($sensor.Hardware) $($sensor.Name)"
          Value = [math]::Round([double]$sensor.Value)
          Source = "Plokar Sensor Engine"
        }
      }
    } catch {}
  }

  return $readings
}

function Select-Temperature($readings, $patterns) {
  foreach ($pattern in $patterns) {
    $match = $readings | Where-Object { $_.Name -match $pattern } | Select-Object -First 1
    if ($match) { return $match }
  }

  return $null
}

function Get-NvidiaTemperature {
  try {
    $command = Get-Command nvidia-smi.exe -ErrorAction SilentlyContinue
    if (-not $command) { return $null }

    $output = & $command.Source --query-gpu=temperature.gpu --format=csv,noheader,nounits 2>$null
    $first = $output | Select-Object -First 1
    if ($first -match "^\s*(\d+(?:\.\d+)?)") {
      return [pscustomobject]@{
        Name = "NVIDIA GPU"
        Value = [math]::Round([double]$matches[1])
        Source = "NVIDIA Driver"
      }
    }
  } catch {}

  return $null
}

function Get-AcpiTemperature {
  try {
    $zones = Get-CimInstance -Namespace root/wmi -ClassName MSAcpi_ThermalZoneTemperature -ErrorAction Stop
    $temps = $zones | ForEach-Object { Convert-KelvinTenthsToCelsius $_.CurrentTemperature } | Where-Object { $_ -gt 0 -and $_ -lt 130 }
    $temp = $temps | Select-Object -First 1
    if ($temp) {
      return [pscustomobject]@{
        Name = "ACPI Thermal Zone"
        Value = $temp
        Source = "Windows ACPI"
      }
    }
  } catch {}

  return $null
}

function Get-DiskTemperature {
  try {
    $counters = Get-PhysicalDisk | Get-StorageReliabilityCounter
    $temp = $counters | Where-Object { $_.Temperature -gt 0 -and $_.Temperature -lt 130 } | Select-Object -First 1
    if ($temp) {
      return [pscustomobject]@{
        Name = "Storage Device"
        Value = [math]::Round([double]$temp.Temperature)
        Source = "Windows Storage"
      }
    }
  } catch {}

  return $null
}

function Get-CpuUsage {
  try {
    $cpu = Get-CimInstance Win32_Processor -ErrorAction Stop | Select-Object -First 1
    if ($null -ne $cpu.LoadPercentage) { return [int]$cpu.LoadPercentage }
  } catch {}
  return $null
}

function Get-RamUsage {
  try {
    $os = Get-CimInstance Win32_OperatingSystem -ErrorAction Stop
    $total = [double]$os.TotalVisibleMemorySize
    $free = [double]$os.FreePhysicalMemory
    if ($total -gt 0) { return [math]::Round((($total - $free) / $total) * 100) }
  } catch {}
  return $null
}

function Get-GpuUsage {
  try {
    $samples = Get-Counter '\GPU Engine(*)\Utilization Percentage' -ErrorAction Stop
    $values = $samples.CounterSamples |
      Where-Object { $_.InstanceName -match "engtype_3d|engtype_compute|engtype_graphics" } |
      ForEach-Object { $_.CookedValue }
    if ($values) {
      $sum = ($values | Measure-Object -Sum).Sum
      return [math]::Min(100, [math]::Round($sum))
    }
  } catch {}
  return $null
}

function Get-SsdStatus {
  try {
    $disk = Get-PhysicalDisk -ErrorAction Stop | Select-Object -First 1
    if ($disk.HealthStatus) { return [string]$disk.HealthStatus }
  } catch {}
  return "Unknown"
}

function Get-SystemSnapshot {
  $lhm = Get-LhmTemperature
  $cpuTempReading = Select-Temperature $lhm @("CPU Package", "CPU Core", "CPU")
  $gpuTempReading = Select-Temperature $lhm @("GPU Core", "GPU")
  $ssdTempReading = Select-Temperature $lhm @("SSD", "NVMe", "HDD", "Drive", "Disk")

  if (-not $cpuTempReading) { $cpuTempReading = Get-AcpiTemperature }
  if (-not $gpuTempReading) { $gpuTempReading = Get-NvidiaTemperature }
  if (-not $ssdTempReading) { $ssdTempReading = Get-DiskTemperature }

  $cpuUsage = Get-CpuUsage
  $gpuUsage = Get-GpuUsage
  $ramUsage = Get-RamUsage
  $ssdStatus = Get-SsdStatus

  $score = 100
  foreach ($value in @($cpuTempReading.Value, $gpuTempReading.Value)) {
    if ($null -ne $value -and $value -gt 70) { $score -= [math]::Min(25, ($value - 70) * 2) }
  }
  if ($null -ne $cpuUsage -and $cpuUsage -gt 75) { $score -= 10 }
  if ($null -ne $gpuUsage -and $gpuUsage -gt 75) { $score -= 10 }
  if ($null -ne $ramUsage -and $ramUsage -gt 80) { $score -= 10 }
  $score = [math]::Max(0, [math]::Min(100, [math]::Round($score)))

  $tone = if ($score -ge 75) { "good" } elseif ($score -ge 55) { "warning" } else { "danger" }

  [pscustomobject]@{
    GeneratedAt = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    CpuTemp = New-SensorValue "CPU 온도" $cpuTempReading.Value "°C" $(if ($cpuTempReading) { $cpuTempReading.Source } else { "Sensor access limited" })
    GpuTemp = New-SensorValue "GPU 온도" $gpuTempReading.Value "°C" $(if ($gpuTempReading) { $gpuTempReading.Source } else { "Sensor access limited" })
    SsdTemp = New-SensorValue "SSD 온도" $ssdTempReading.Value "°C" $(if ($ssdTempReading) { $ssdTempReading.Source } else { "Sensor access limited" })
    CpuUsage = New-SensorValue "CPU 사용률" $cpuUsage "%" "Windows"
    GpuUsage = New-SensorValue "GPU 사용률" $gpuUsage "%" $(if ($null -eq $gpuUsage) { "Sensor access limited" } else { "Windows Performance Counter" })
    RamUsage = New-SensorValue "RAM 사용률" $ramUsage "%" "Windows"
    SsdStatus = $ssdStatus
    Score = $score
    Tone = $tone
  }
}

function Set-Card($label, $title, $value, $sub, $tone) {
  $label.Text = $title
  $valueLabel = $label.Tag.Value
  $subLabel = $label.Tag.Sub
  $valueLabel.Text = $value
  $subLabel.Text = $sub

  if ($tone -eq "danger") {
    $valueLabel.ForeColor = [System.Drawing.Color]::FromArgb(210, 55, 55)
  } elseif ($tone -eq "warning") {
    $valueLabel.ForeColor = [System.Drawing.Color]::FromArgb(180, 130, 0)
  } else {
    $valueLabel.ForeColor = [System.Drawing.Color]::FromArgb(0, 140, 96)
  }
}

function New-Card($parent, $x, $y, $w, $h) {
  $panel = New-Object System.Windows.Forms.Panel
  $panel.Left = $x
  $panel.Top = $y
  $panel.Width = $w
  $panel.Height = $h
  $panel.BackColor = [System.Drawing.Color]::White
  $panel.BorderStyle = "FixedSingle"
  $parent.Controls.Add($panel)

  $title = New-Object System.Windows.Forms.Label
  $title.Left = 12
  $title.Top = 10
  $title.Width = $w - 24
  $title.Height = 22
  $title.Font = New-Object System.Drawing.Font -ArgumentList "Segoe UI", 10, ([System.Drawing.FontStyle]::Bold)
  $panel.Controls.Add($title)

  $value = New-Object System.Windows.Forms.Label
  $value.Left = 12
  $value.Top = 34
  $value.Width = $w - 24
  $value.Height = 36
  $value.Font = New-Object System.Drawing.Font -ArgumentList "Segoe UI", 18, ([System.Drawing.FontStyle]::Bold)
  $panel.Controls.Add($value)

  $sub = New-Object System.Windows.Forms.Label
  $sub.Left = 12
  $sub.Top = 72
  $sub.Width = $w - 24
  $sub.Height = $h - 76
  $sub.ForeColor = [System.Drawing.Color]::FromArgb(90, 90, 90)
  $sub.Font = New-Object System.Drawing.Font -ArgumentList "Segoe UI", 9
  $panel.Controls.Add($sub)

  $title.Tag = @{ Value = $value; Sub = $sub }
  return $title
}

function Show-FluxWindow {
  Add-Type -AssemblyName System.Windows.Forms
  Add-Type -AssemblyName System.Drawing
  [System.Windows.Forms.Application]::EnableVisualStyles()

  $script:currentSnapshot = Get-SystemSnapshot

  $form = New-Object System.Windows.Forms.Form
  $form.Text = "Flux Analyzer Beta"
  $form.StartPosition = "CenterScreen"
  $form.Width = 920
  $form.Height = 680
  $form.MinimumSize = New-Object System.Drawing.Size -ArgumentList 820, 620
  $form.BackColor = [System.Drawing.Color]::FromArgb(245, 246, 248)
  $form.Font = New-Object System.Drawing.Font -ArgumentList "Segoe UI", 10

  $iconPath = Join-Path $PSScriptRoot "logo.ico"
  if (Test-Path $iconPath) {
    try { $form.Icon = New-Object System.Drawing.Icon -ArgumentList $iconPath } catch {}
  }

  $header = New-Object System.Windows.Forms.Panel
  $header.Dock = "Top"
  $header.Height = 82
  $header.BackColor = [System.Drawing.Color]::White
  $form.Controls.Add($header)

  $logoPath = Join-Path $PSScriptRoot "logo.png"
  if (Test-Path $logoPath) {
    $logo = New-Object System.Windows.Forms.PictureBox
    $logo.Left = 18
    $logo.Top = 15
    $logo.Width = 58
    $logo.Height = 44
    $logo.SizeMode = "Zoom"
    $logo.Image = [System.Drawing.Image]::FromFile($logoPath)
    $header.Controls.Add($logo)
  }

  $title = New-Object System.Windows.Forms.Label
  $title.Left = 88
  $title.Top = 15
  $title.Width = 340
  $title.Height = 30
  $title.Text = "Flux Analyzer Beta"
  $title.Font = New-Object System.Drawing.Font -ArgumentList "Segoe UI", 16, ([System.Drawing.FontStyle]::Bold)
  $header.Controls.Add($title)

  $pcStatus = New-Object System.Windows.Forms.Label
  $pcStatus.Left = 90
  $pcStatus.Top = 48
  $pcStatus.Width = 500
  $pcStatus.Height = 22
  $pcStatus.ForeColor = [System.Drawing.Color]::FromArgb(80, 80, 80)
  $header.Controls.Add($pcStatus)

  $langButton = New-Object System.Windows.Forms.Button
  $langButton.Text = "KO"
  $langButton.Width = 58
  $langButton.Height = 34
  $langButton.Left = 735
  $langButton.Top = 23
  $langButton.Anchor = "Top,Right"
  $header.Controls.Add($langButton)

  $refreshButton = New-Object System.Windows.Forms.Button
  $refreshButton.Text = "Refresh"
  $refreshButton.Width = 92
  $refreshButton.Height = 34
  $refreshButton.Left = 805
  $refreshButton.Top = 23
  $refreshButton.Anchor = "Top,Right"
  $header.Controls.Add($refreshButton)

  $advancedButton = New-Object System.Windows.Forms.Button
  $advancedButton.Text = "Advanced"
  $advancedButton.Width = 92
  $advancedButton.Height = 34
  $advancedButton.Left = 635
  $advancedButton.Top = 23
  $advancedButton.Anchor = "Top,Right"
  $header.Controls.Add($advancedButton)

  $statusLabel = New-Object System.Windows.Forms.Label
  $statusLabel.Left = 18
  $statusLabel.Top = 96
  $statusLabel.Width = 620
  $statusLabel.Height = 24
  $statusLabel.Text = "Scanning complete"
  $form.Controls.Add($statusLabel)

  $progress = New-Object System.Windows.Forms.ProgressBar
  $progress.Left = 690
  $progress.Top = 96
  $progress.Width = 210
  $progress.Height = 18
  $progress.Anchor = "Top,Right"
  $progress.Minimum = 0
  $progress.Maximum = 100
  $progress.Value = 100
  $form.Controls.Add($progress)

  $scoreCard = New-Card $form 18 130 200 118
  $cpuCard = New-Card $form 234 130 200 118
  $gpuCard = New-Card $form 450 130 200 118
  $ramCard = New-Card $form 666 130 234 118
  $ssdCard = New-Card $form 18 262 200 118
  $causeCard = New-Card $form 234 262 416 118
  $recommendCard = New-Card $form 666 262 234 118

  $tabs = New-Object System.Windows.Forms.TabControl
  $tabs.Left = 18
  $tabs.Top = 398
  $tabs.Width = 882
  $tabs.Height = 220
  $tabs.Anchor = "Left,Right,Top,Bottom"
  $form.Controls.Add($tabs)

  $sensorPage = New-Object System.Windows.Forms.TabPage
  $sensorPage.Text = "Sensors"
  $tabs.TabPages.Add($sensorPage)

  $grid = New-Object System.Windows.Forms.DataGridView
  $grid.Dock = "Fill"
  $grid.AllowUserToAddRows = $false
  $grid.AllowUserToDeleteRows = $false
  $grid.ReadOnly = $true
  $grid.RowHeadersVisible = $false
  $grid.AutoSizeColumnsMode = "Fill"
  $grid.BackgroundColor = [System.Drawing.Color]::White
  $sensorPage.Controls.Add($grid)
  [void]$grid.Columns.Add("Metric", "Metric")
  [void]$grid.Columns.Add("Value", "Value")
  [void]$grid.Columns.Add("Source", "Source")

  $analysisPage = New-Object System.Windows.Forms.TabPage
  $analysisPage.Text = "Analysis"
  $tabs.TabPages.Add($analysisPage)
  $analysisBox = New-Object System.Windows.Forms.TextBox
  $analysisBox.Dock = "Fill"
  $analysisBox.Multiline = $true
  $analysisBox.ReadOnly = $true
  $analysisBox.BorderStyle = "None"
  $analysisBox.Font = New-Object System.Drawing.Font -ArgumentList "Segoe UI", 11
  $analysisPage.Controls.Add($analysisBox)

  $script:language = "en"

  function Render-FluxUi {
    param($lang)
    $grid.Rows.Clear()
    [void]$grid.Rows.Add("CPU Temperature", $script:currentSnapshot.CpuTemp.DisplayEn, $script:currentSnapshot.CpuTemp.Source)
    [void]$grid.Rows.Add("GPU Temperature", $script:currentSnapshot.GpuTemp.DisplayEn, $script:currentSnapshot.GpuTemp.Source)
    [void]$grid.Rows.Add("SSD Temperature", $script:currentSnapshot.SsdTemp.DisplayEn, $script:currentSnapshot.SsdTemp.Source)
    [void]$grid.Rows.Add("CPU Usage", $script:currentSnapshot.CpuUsage.DisplayEn, $script:currentSnapshot.CpuUsage.Source)
    [void]$grid.Rows.Add("GPU Usage", $script:currentSnapshot.GpuUsage.DisplayEn, $script:currentSnapshot.GpuUsage.Source)
    [void]$grid.Rows.Add("RAM Usage", $script:currentSnapshot.RamUsage.DisplayEn, $script:currentSnapshot.RamUsage.Source)

    $tone = $script:currentSnapshot.Tone
    if ($lang -eq "ko") {
      $title.Text = "Flux Analyzer Beta"
      $pcStatus.Text = "현재 PC 상태: " + $(if ($tone -eq "good") { "좋음" } elseif ($tone -eq "warning") { "주의" } else { "위험" })
      $refreshButton.Text = "새로고침"
      $advancedButton.Text = "고급"
      $langButton.Text = "EN"
      $statusLabel.Text = "스캔 완료"
      $sensorPage.Text = "센서"
      $analysisPage.Text = "분석"
      $grid.Columns[0].HeaderText = "항목"
      $grid.Columns[1].HeaderText = "값"
      $grid.Columns[2].HeaderText = "출처"
      Set-Card $scoreCard "Flux Score" "$($script:currentSnapshot.Score)점" "상태를 점수로 보여줍니다" $tone
      Set-Card $cpuCard "CPU 온도" $script:currentSnapshot.CpuTemp.Display $script:currentSnapshot.CpuTemp.Source $tone
      Set-Card $gpuCard "GPU 온도" $script:currentSnapshot.GpuTemp.Display $script:currentSnapshot.GpuTemp.Source $tone
      Set-Card $ramCard "RAM 사용률" $script:currentSnapshot.RamUsage.Display $script:currentSnapshot.RamUsage.Source "good"
      Set-Card $ssdCard "SSD 상태" $script:currentSnapshot.SsdStatus "온도: $($script:currentSnapshot.SsdTemp.Display)" "good"
      Set-Card $causeCard "발열 원인 분석" "고부하 작업 확인" "CPU/GPU 사용률과 온도를 함께 확인하세요" $tone
      Set-Card $recommendCard "최적화 추천" "안전 모드" "불필요한 앱 종료, 균형 전원 모드 확인" "good"
      $analysisBox.Text = "온도를 읽지 못하는 항목은 오류가 아니라 센서 접근 제한입니다.`r`n`r`n일부 CPU/GPU 온도는 관리자 권한 또는 별도 센서 엔진이 필요할 수 있습니다.`r`n`r`n고급 센서 접근은 나중에 별도 버튼으로 제공됩니다."
    } else {
      $title.Text = "Flux Analyzer Beta"
      $pcStatus.Text = "Current PC status: " + $(if ($tone -eq "good") { "Good" } elseif ($tone -eq "warning") { "Warning" } else { "Risk" })
      $refreshButton.Text = "Refresh"
      $advancedButton.Text = "Advanced"
      $langButton.Text = "KO"
      $statusLabel.Text = "Scanning complete"
      $sensorPage.Text = "Sensors"
      $analysisPage.Text = "Analysis"
      $grid.Columns[0].HeaderText = "Metric"
      $grid.Columns[1].HeaderText = "Value"
      $grid.Columns[2].HeaderText = "Source"
      Set-Card $scoreCard "Flux Score" "$($script:currentSnapshot.Score)" "System efficiency score" $tone
      Set-Card $cpuCard "CPU Temperature" $script:currentSnapshot.CpuTemp.DisplayEn $script:currentSnapshot.CpuTemp.Source $tone
      Set-Card $gpuCard "GPU Temperature" $script:currentSnapshot.GpuTemp.DisplayEn $script:currentSnapshot.GpuTemp.Source $tone
      Set-Card $ramCard "RAM Usage" $script:currentSnapshot.RamUsage.DisplayEn $script:currentSnapshot.RamUsage.Source "good"
      Set-Card $ssdCard "SSD Status" $script:currentSnapshot.SsdStatus "Temp: $($script:currentSnapshot.SsdTemp.DisplayEn)" "good"
      Set-Card $causeCard "Heat Cause" "High load check" "Review CPU/GPU usage and temperatures together" $tone
      Set-Card $recommendCard "Optimization" "Safe mode" "Close unused apps and check balanced power mode" "good"
      $analysisBox.Text = "If a temperature value is unavailable, it means sensor access is limited, not that the app failed.`r`n`r`nSome CPU/GPU temperatures may require administrator permission or a separate sensor engine.`r`n`r`nAdvanced sensor access will be provided through a separate action."
    }
  }

  $langButton.Add_Click({
    if ($script:language -eq "en") { $script:language = "ko" } else { $script:language = "en" }
    Render-FluxUi $script:language
  })

  $refreshButton.Add_Click({
    $statusLabel.Text = if ($script:language -eq "ko") { "스캔 중..." } else { "Scanning..." }
    $progress.Style = "Marquee"
    $form.Refresh()
    $script:currentSnapshot = Get-SystemSnapshot
    $progress.Style = "Blocks"
    $progress.Value = 100
    Render-FluxUi $script:language
  })

  $advancedButton.Add_Click({
    if ($script:language -eq "ko") {
      [System.Windows.Forms.MessageBox]::Show("일부 CPU/GPU 온도를 읽으려면 관리자 권한이나 별도 센서 엔진이 필요할 수 있습니다. 현재 Beta는 기본 모드에서 가능한 센서만 안전하게 읽습니다.", "고급 센서 접근", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information) | Out-Null
    } else {
      [System.Windows.Forms.MessageBox]::Show("Some CPU/GPU temperatures may require administrator permission or a separate sensor engine. Flux Beta safely reads only available sensors in default mode.", "Advanced sensor access", [System.Windows.Forms.MessageBoxButtons]::OK, [System.Windows.Forms.MessageBoxIcon]::Information) | Out-Null
    }
  })

  Render-FluxUi $script:language
  [void][System.Windows.Forms.Application]::Run($form)
}

try {
  Show-FluxWindow
  exit 0
} catch {
  Write-Host "Plokar Flux Analyzer failed."
  Write-Host $_.Exception.ToString()
  exit 1
}
