param(
  [string]$ProjectRoot = (Split-Path -Parent $PSScriptRoot)
)

$ErrorActionPreference = 'Stop'
Add-Type -AssemblyName System.Drawing

$sourcePath = Join-Path $ProjectRoot 'admin\assets\img\sidebar_program_logo.png'
$launcherDir = Join-Path $ProjectRoot 'launcher'
$androidRes = Join-Path $ProjectRoot 'mobile\android\app\src\main\res'

if (-not (Test-Path -LiteralPath $sourcePath)) {
  throw "Logo source not found: $sourcePath"
}

function New-RoundedPath([System.Drawing.RectangleF]$rect, [float]$radius) {
  $path = [System.Drawing.Drawing2D.GraphicsPath]::new()
  $diameter = $radius * 2
  $path.AddArc($rect.Left, $rect.Top, $diameter, $diameter, 180, 90)
  $path.AddArc($rect.Right - $diameter, $rect.Top, $diameter, $diameter, 270, 90)
  $path.AddArc($rect.Right - $diameter, $rect.Bottom - $diameter, $diameter, $diameter, 0, 90)
  $path.AddArc($rect.Left, $rect.Bottom - $diameter, $diameter, $diameter, 90, 90)
  $path.CloseFigure()
  return $path
}

function Get-LogoBounds([System.Drawing.Bitmap]$bitmap) {
  $minX = $bitmap.Width
  $minY = $bitmap.Height
  $maxX = 0
  $maxY = 0
  for ($y = 0; $y -lt $bitmap.Height; $y += 2) {
    for ($x = 0; $x -lt $bitmap.Width; $x += 2) {
      $pixel = $bitmap.GetPixel($x, $y)
      if ($pixel.A -gt 8 -and ($pixel.R -lt 246 -or $pixel.G -lt 246 -or $pixel.B -lt 246)) {
        if ($x -lt $minX) { $minX = $x }
        if ($y -lt $minY) { $minY = $y }
        if ($x -gt $maxX) { $maxX = $x }
        if ($y -gt $maxY) { $maxY = $y }
      }
    }
  }
  $pad = [Math]::Max(4, [Math]::Round([Math]::Max($maxX - $minX, $maxY - $minY) * 0.025))
  $left = [Math]::Max(0, $minX - $pad)
  $top = [Math]::Max(0, $minY - $pad)
  $right = [Math]::Min($bitmap.Width - 1, $maxX + $pad)
  $bottom = [Math]::Min($bitmap.Height - 1, $maxY + $pad)
  return [System.Drawing.Rectangle]::new($left, $top, $right - $left + 1, $bottom - $top + 1)
}

function New-LogoIcon([System.Drawing.Bitmap]$source, [System.Drawing.Rectangle]$sourceRect, [int]$size) {
  $bitmap = [System.Drawing.Bitmap]::new($size, $size, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
  $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
  try {
    $graphics.Clear([System.Drawing.Color]::Transparent)
    $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
    $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
    $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
    $outer = [System.Drawing.RectangleF]::new($size * 0.02, $size * 0.02, $size * 0.96, $size * 0.96)
    $path = New-RoundedPath $outer ($size * 0.22)
    try {
      $graphics.SetClip($path)
      $graphics.FillRectangle([System.Drawing.Brushes]::White, $outer)
      $contentSize = $size * 0.82
      $destination = [System.Drawing.RectangleF]::new(($size - $contentSize) / 2, ($size - $contentSize) / 2, $contentSize, $contentSize)
      $graphics.DrawImage($source, $destination, $sourceRect, [System.Drawing.GraphicsUnit]::Pixel)
      $graphics.ResetClip()
      $borderWidth = [Math]::Max(1.0, $size * 0.012)
      $pen = [System.Drawing.Pen]::new([System.Drawing.Color]::FromArgb(80, 19, 121, 224), $borderWidth)
      try { $graphics.DrawPath($pen, $path) } finally { $pen.Dispose() }
    } finally {
      $path.Dispose()
    }
  } finally {
    $graphics.Dispose()
  }
  return $bitmap
}

function New-AdaptiveForeground([System.Drawing.Bitmap]$source, [System.Drawing.Rectangle]$sourceRect) {
  $cropped = [System.Drawing.Bitmap]::new($sourceRect.Width, $sourceRect.Height, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
  for ($y = 0; $y -lt $sourceRect.Height; $y++) {
    for ($x = 0; $x -lt $sourceRect.Width; $x++) {
      $pixel = $source.GetPixel($sourceRect.X + $x, $sourceRect.Y + $y)
      if ($pixel.R -gt 245 -and $pixel.G -gt 245 -and $pixel.B -gt 245) {
        $cropped.SetPixel($x, $y, [System.Drawing.Color]::Transparent)
      } else {
        $cropped.SetPixel($x, $y, $pixel)
      }
    }
  }

  $bitmap = [System.Drawing.Bitmap]::new(432, 432, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
  $graphics = [System.Drawing.Graphics]::FromImage($bitmap)
  try {
    $graphics.Clear([System.Drawing.Color]::Transparent)
    $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::AntiAlias
    $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
    $graphics.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
    $graphics.DrawImage($cropped, [System.Drawing.RectangleF]::new(76, 76, 280, 280))
  } finally {
    $graphics.Dispose()
    $cropped.Dispose()
  }
  return $bitmap
}

function Save-Png([System.Drawing.Bitmap]$bitmap, [string]$path) {
  $directory = Split-Path -Parent $path
  [System.IO.Directory]::CreateDirectory($directory) | Out-Null
  $bitmap.Save($path, [System.Drawing.Imaging.ImageFormat]::Png)
}

function Convert-ToPngBytes([System.Drawing.Bitmap]$bitmap) {
  $stream = [System.IO.MemoryStream]::new()
  try {
    $bitmap.Save($stream, [System.Drawing.Imaging.ImageFormat]::Png)
    return ,$stream.ToArray()
  } finally {
    $stream.Dispose()
  }
}

function Write-MultiSizeIco([string]$path, [System.Collections.IEnumerable]$items) {
  $payloads = @()
  foreach ($item in $items) {
    $payloads += [pscustomobject]@{ Size = [int]$item.Size; Bytes = [byte[]](Convert-ToPngBytes $item.Bitmap) }
  }
  $stream = [System.IO.File]::Open($path, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)
  $writer = [System.IO.BinaryWriter]::new($stream)
  try {
    $writer.Write([uint16]0)
    $writer.Write([uint16]1)
    $writer.Write([uint16]$payloads.Count)
    $offset = 6 + (16 * $payloads.Count)
    foreach ($payload in $payloads) {
      $dimension = if ($payload.Size -ge 256) { 0 } else { $payload.Size }
      $writer.Write([byte]$dimension)
      $writer.Write([byte]$dimension)
      $writer.Write([byte]0)
      $writer.Write([byte]0)
      $writer.Write([uint16]1)
      $writer.Write([uint16]32)
      $writer.Write([uint32]$payload.Bytes.Length)
      $writer.Write([uint32]$offset)
      $offset += $payload.Bytes.Length
    }
    foreach ($payload in $payloads) { $writer.Write($payload.Bytes) }
  } finally {
    $writer.Dispose()
    $stream.Dispose()
  }
}

$source = [System.Drawing.Bitmap]::new($sourcePath)
$generated = [System.Collections.Generic.List[object]]::new()
try {
  $sourceRect = Get-LogoBounds $source
  $androidSizes = [ordered]@{
    'mipmap-mdpi\ic_launcher.png' = 48
    'mipmap-hdpi\ic_launcher.png' = 72
    'mipmap-xhdpi\ic_launcher.png' = 96
    'mipmap-xxhdpi\ic_launcher.png' = 144
    'mipmap-xxxhdpi\ic_launcher.png' = 192
  }
  foreach ($entry in $androidSizes.GetEnumerator()) {
    $bitmap = New-LogoIcon $source $sourceRect $entry.Value
    try { Save-Png $bitmap (Join-Path $androidRes $entry.Key) } finally { $bitmap.Dispose() }
  }

  $foreground = New-AdaptiveForeground $source $sourceRect
  try { Save-Png $foreground (Join-Path $androidRes 'drawable-nodpi\ic_launcher_foreground.png') } finally { $foreground.Dispose() }

  foreach ($size in @(16, 24, 32, 48, 64, 128, 256)) {
    $generated.Add([pscustomobject]@{ Size = $size; Bitmap = (New-LogoIcon $source $sourceRect $size) })
  }
  [System.IO.Directory]::CreateDirectory($launcherDir) | Out-Null
  Write-MultiSizeIco (Join-Path $launcherDir 'NetworkCustomers.ico') $generated
} finally {
  foreach ($item in $generated) { $item.Bitmap.Dispose() }
  $source.Dispose()
}

Write-Host "Generated Android launcher icons and Windows ICO from $sourcePath"
