name: Build and Deploy LSFE

on:
  push:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: win-runner-01

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Clean previous publish output
        shell: pwsh
        run: |
          Remove-Item -Recurse -Force "C:\ci-output\webapi" -ErrorAction SilentlyContinue

      - name: Publish WebApi
        shell: pwsh
        run: dotnet publish .\LSFE.API\LSFE.API.csproj -c Release -o C:\ci-output\webapi

      # ---- Generate production config from Gitea Actions secrets (never committed to git) ----
      - name: Write production appsettings - WebApi
        shell: pwsh
        env:
          GROQ_KEY: ${{ secrets.LLI_SFE_PROD_GROQ_API_KEY }}
          JWT_SECRET: ${{ secrets.LLI_SFE_PROD_JWT_SECRET }}
          DB_CONN: ${{ secrets.LLI_SFE_PROD_DB_CONNECTION }}
        run: |
          $config = @{
            Groq = @{
              ApiKey = $env:GROQ_KEY
              ApiUrl = "https://api.groq.com/openai/v1/chat/completions"
              Model = "llama-3.1-8b-instant"
            }
            JWT = @{
              ValidAudience = "https://lloydwebapi.lloydlab.com:2021"
              ValidIssuer = "https://lloydwebapi.lloydlab.com:2021"
              Secret = $env:JWT_SECRET
            }
            ConnectionStrings = @{
              DefaultConnection = $env:DB_CONN
            }
          }

          $json = $config | ConvertTo-Json -Depth 5
          $json | Out-File -FilePath "C:\ci-output\webapi\appsettings.Production.json" -Encoding utf8
          Write-Host "Wrote appsettings.Production.json to webapi output (secret values not echoed)"
          exit 0

      # ---- Backup current live deployment before touching anything ----
      # NOTE: this backs up Content too (harmless - it's just a point-in-time copy
      # and is never used to restore Content, see rollback step below).
      - name: Backup current live files
        shell: pwsh
        run: |
          $stamp = Get-Date -Format "yyyyMMdd-HHmmss"
          New-Item -ItemType Directory -Force -Path "C:\backups\$stamp" | Out-Null

          if (Test-Path "C:\inetpub\LSFE-api") {
            robocopy "C:\inetpub\LSFE-api" "C:\backups\$stamp\webapi" /MIR /R:2 /W:3 /XD Content | Out-Null
          }

          $stamp | Out-File -FilePath "C:\backups\latest.txt" -Encoding ascii -NoNewline

          # Keep only the last 5 backups to avoid filling the disk
          $all = Get-ChildItem "C:\backups" -Directory | Sort-Object Name -Descending
          if ($all.Count -gt 5) {
            $all | Select-Object -Skip 5 | Remove-Item -Recurse -Force
          }

          Write-Host "Backed up current deployment to C:\backups\$stamp (Content excluded - never backed up or restored)"
          exit 0

      - name: Stop app pools
        shell: pwsh
        run: |
          Import-Module WebAdministration
          Stop-WebAppPool -Name "LSFE-Api" -ErrorAction SilentlyContinue
          Start-Sleep -Seconds 3

      - name: Deploy WebApi files
        id: deploy_api
        shell: pwsh
        run: |
          # Deploy everything EXCEPT the Content folder (and its subfolders, Images/Uploads).
          # /XD Content excludes the directory by NAME, which robocopy matches reliably
          # against the source tree it walks, at any depth - so wwwroot\Content and
          # everything under it (Images, Uploads) is never copied over or deleted.
          # This prevents /MIR from purging/replacing the live C:\inetpub\LSFE-api\wwwroot\Content folder.
          robocopy "C:\ci-output\webapi" "C:\inetpub\LSFE-api" /MIR /R:3 /W:5 /XD Content
          $rc = $LASTEXITCODE
          Write-Host "ROBOCOPY EXIT CODE: $rc"
          if ($rc -ge 8) {
            throw "robocopy failed for WebApi with exit code $rc"
          }
          exit 0

      - name: Start app pools
        shell: pwsh
        run: |
          Import-Module WebAdministration
          Start-WebAppPool -Name "LSFE-Api"

      - name: Verify app pools are running
        shell: pwsh
        run: |
          Start-Sleep -Seconds 3
          Import-Module WebAdministration
          $api = Get-WebAppPoolState -Name "LSFE-Api"
          Write-Host "LSFE-Api: $($api.Value)"
          if ($api.Value -ne "Started") {
            throw "One or more app pools failed to start"
          }

      # ---- Rollback path: only runs if any prior step in this job failed ----
      - name: ROLLBACK - restore previous backup
        if: failure()
        shell: pwsh
        run: |
          $stamp = (Get-Content "C:\backups\latest.txt" -Raw).Trim()
          $backupPath = "C:\backups\$stamp"
          Write-Host "Deployment failed - rolling back to backup: $backupPath"

          Import-Module WebAdministration
          Stop-WebAppPool -Name "LSFE-Api" -ErrorAction SilentlyContinue
          Start-Sleep -Seconds 3

          if (Test-Path "$backupPath\webapi") {
            # /XD Content here is critical: the backup was taken BEFORE this deploy
            # attempt, so it holds a stale snapshot of Content. Without this exclusion,
            # rolling back would blow away any files/uploads written to Content since
            # the backup was made. Content must never be touched by CI/CD, including rollback.
            robocopy "$backupPath\webapi" "C:\inetpub\LSFE-api" /MIR /R:3 /W:5 /XD Content | Out-Null
          }

          Start-WebAppPool -Name "LSFE-Api"

          Write-Host "Rollback complete. Restored from $backupPath (Content left untouched)"
          exit 0

      - name: ROLLBACK - verify pools after restore
        if: failure()
        shell: pwsh
        run: |
          Start-Sleep -Seconds 3
          Import-Module WebAdministration
          $api = Get-WebAppPoolState -Name "LSFE-Api"

          Write-Host "After rollback - LSFE-Api: $($api.Value)"

          if ($api.Value -ne "Started") {
            Write-Host "WARNING: app pool still not running after rollback. Manual intervention needed."
          }