<#
.SYNOPSIS
    제3자 의존성 벤더링 (NETWORKED 빌드 머신 전용) — firmware/third_party 채우기.

.DESCRIPTION
    폐쇄망(air-gapped) 타깃으로 전달하기 위해, 빌드/스테이징 머신에서 핀 고정된
    제3자 의존성을 내려받아 SHA-256 으로 무결성을 검증한 뒤 firmware/third_party
    아래에 펼친다. **네트워크가 허용되는 유일한 단계**다. 이후 build.ps1 은
    네트워크 없이 빌드한다.

    벤더링 대상(핀 고정):
      - STM32CubeF4   (HAL + CMSIS + startup/system)   TODO(vendor): 버전 핀 확정
      - FreeRTOS-Kernel (네이티브 API, ARM_CM4F 포트)   TODO(vendor)
      - lwip          (LwIP TCP/IP + apps/sntp)          TODO(vendor)
      - mbedtls       (TLS 1.2 클라이언트)               TODO(vendor)

    중요: 아래 $Deps 의 Url/Sha256/Tag 는 운영 환경에서 **사용할 정확한 핀 버전**으로
    교체해야 한다. SHA-256 미설정('TODO') 인 항목은 다운로드 후 계산된 해시를
    출력만 하고(최초 1회 기록용) 검증은 건너뛴다 — 기록 후 반드시 채워 넣을 것.

.PARAMETER Force
    이미 존재하는 third_party 하위 트리를 덮어쓴다(재벤더링).

.PARAMETER KeepArchives
    내려받은 압축 파일을 third_party/_archives 에 보존한다(오프라인 재현용).

.EXAMPLE
    pwsh firmware/scripts/vendor.ps1
    pwsh firmware/scripts/vendor.ps1 -Force -KeepArchives
#>
[CmdletBinding()]
param(
    [switch]$Force,
    [switch]$KeepArchives
)

$ErrorActionPreference = 'Stop'
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

$ScriptDir  = Split-Path -Parent $MyInvocation.MyCommand.Path
$FwRoot     = Split-Path -Parent $ScriptDir
$ThirdParty = Join-Path $FwRoot 'third_party'
$ArchiveDir = Join-Path $ThirdParty '_archives'

# =============================================================================
# 핀 고정 의존성 목록
#   Name   : third_party 아래 디렉터리명 (CMakeLists 의 경로와 일치해야 함)
#   Tag    : 릴리스/태그(추적용)
#   Url    : 다운로드 URL (release tarball/zip)
#   Sha256 : 압축 파일 SHA-256 (소문자 hex). 'TODO' 면 검증 생략(해시 출력만).
#   Strip  : 압축 최상위 폴더를 벗겨낼지(대부분 release 는 단일 최상위 폴더)
#
#   TODO(vendor): Url/Sha256/Tag 를 운영에서 쓸 정확한 핀 버전으로 교체.
#   STM32CubeF4 는 GitHub release zip 또는 ST 공식 배포본을 사용한다.
# =============================================================================
$Deps = @(
    @{
        Name   = 'STM32CubeF4'
        Tag    = 'v1.28.0'
        Url    = 'https://github.com/STMicroelectronics/STM32CubeF4/archive/refs/tags/v1.28.0.zip'
        Sha256 = 'TODO'   # TODO(vendor): 실제 zip SHA-256 기입
        Strip  = $true
    },
    @{
        Name   = 'FreeRTOS-Kernel'
        Tag    = 'V11.1.0'
        Url    = 'https://github.com/FreeRTOS/FreeRTOS-Kernel/archive/refs/tags/V11.1.0.zip'
        Sha256 = 'TODO'   # TODO(vendor)
        Strip  = $true
    },
    @{
        Name   = 'lwip'
        Tag    = 'STABLE-2_2_0_RELEASE'
        Url    = 'https://github.com/lwip-tcpip/lwip/archive/refs/tags/STABLE-2_2_0_RELEASE.zip'
        Sha256 = 'TODO'   # TODO(vendor)
        Strip  = $true
    },
    @{
        Name   = 'mbedtls'
        Tag    = 'v3.6.2'
        Url    = 'https://github.com/Mbed-TLS/mbedtls/releases/download/mbedtls-3.6.2/mbedtls-3.6.2.tar.bz2'
        Sha256 = 'TODO'   # TODO(vendor): release tarball 은 공식 SHA-256 제공됨
        Strip  = $true
    }
)

New-Item -ItemType Directory -Force -Path $ThirdParty | Out-Null
if ($KeepArchives) { New-Item -ItemType Directory -Force -Path $ArchiveDir | Out-Null }

function Get-FileSha256([string]$path) {
    (Get-FileHash -Algorithm SHA256 -Path $path).Hash.ToLowerInvariant()
}

# 압축 해제(zip / tar.bz2 / tar.gz). tar 는 Windows 10+ 내장 bsdtar 사용.
function Expand-Archive2([string]$archive, [string]$dest) {
    New-Item -ItemType Directory -Force -Path $dest | Out-Null
    if ($archive -match '\.zip$') {
        Expand-Archive -Path $archive -DestinationPath $dest -Force
    }
    elseif ($archive -match '\.(tar\.bz2|tbz2|tar\.gz|tgz|tar\.xz)$') {
        if (-not (Get-Command 'tar' -ErrorAction SilentlyContinue)) {
            throw "tar 가 필요합니다(.tar.* 해제). Windows 10+ 내장 tar 또는 git tar 사용."
        }
        & tar -xf $archive -C $dest
        if ($LASTEXITCODE -ne 0) { throw "tar 해제 실패: $archive" }
    }
    else {
        throw "지원하지 않는 압축 형식: $archive"
    }
}

foreach ($dep in $Deps) {
    $name   = $dep.Name
    $target = Join-Path $ThirdParty $name

    Write-Host "──────────────────────────────────────────────" -ForegroundColor Cyan
    Write-Host " 벤더링: $name ($($dep.Tag))" -ForegroundColor Cyan

    if ((Test-Path $target) -and -not $Force) {
        Write-Host "  이미 존재 — 건너뜀(재벤더링은 -Force). $target" -ForegroundColor Yellow
        continue
    }
    if (Test-Path $target) {
        Remove-Item -Recurse -Force $target
    }

    # ── 다운로드 ─────────────────────────────────────────────────────────────
    $tmp = New-Item -ItemType Directory -Force `
        -Path (Join-Path ([IO.Path]::GetTempPath()) ("vendor_" + [Guid]::NewGuid()))
    $fileName = [IO.Path]::GetFileName(([Uri]$dep.Url).AbsolutePath)
    $archive  = Join-Path $tmp $fileName

    Write-Host "  다운로드: $($dep.Url)"
    Invoke-WebRequest -Uri $dep.Url -OutFile $archive -UseBasicParsing

    # ── 무결성 검증(SHA-256) ────────────────────────────────────────────────
    $actual = Get-FileSha256 $archive
    if ($dep.Sha256 -eq 'TODO' -or [string]::IsNullOrWhiteSpace($dep.Sha256)) {
        Write-Host "  [경고] SHA-256 미설정 — 검증 생략. 계산값을 기록하세요:" -ForegroundColor Yellow
        Write-Host "         $name : $actual" -ForegroundColor Yellow
    }
    elseif ($actual -ne $dep.Sha256.ToLowerInvariant()) {
        throw "SHA-256 불일치($name)`n  기대: $($dep.Sha256)`n  실제: $actual"
    }
    else {
        Write-Host "  SHA-256 확인됨: $actual" -ForegroundColor Green
    }

    # ── 해제 + 최상위 폴더 벗기기 ────────────────────────────────────────────
    $extract = Join-Path $tmp 'x'
    Expand-Archive2 $archive $extract

    if ($dep.Strip) {
        $top = @(Get-ChildItem -Directory $extract)
        if ($top.Count -eq 1) {
            Move-Item -Path $top[0].FullName -Destination $target
        }
        else {
            # 최상위가 단일 폴더가 아니면 그대로 이동.
            Move-Item -Path $extract -Destination $target
        }
    }
    else {
        Move-Item -Path $extract -Destination $target
    }

    if ($KeepArchives) {
        Copy-Item -Path $archive -Destination (Join-Path $ArchiveDir $fileName) -Force
    }
    Remove-Item -Recurse -Force $tmp -ErrorAction SilentlyContinue

    Write-Host "  완료 → $target" -ForegroundColor Green
}

Write-Host "──────────────────────────────────────────────" -ForegroundColor Cyan
Write-Host " 벤더링 완료. 이제 폐쇄망 빌드 가능: pwsh firmware/scripts/build.ps1" -ForegroundColor Green
Write-Host " TODO(vendor): 위 출력된 SHA-256 값을 \$Deps 에 채워 재현성을 고정하세요." -ForegroundColor Yellow
