name: Release

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:
    inputs:
      tag:
        description: 'Release tag'
        required: true
        type: string
      is_prerelease:
        description: 'Pre-release'
        required: false
        type: boolean
        default: false

env:
  DOTNET_VERSION: '10.0.x'
  Solution_Name: LanMountainDesktop.slnx

jobs:
  prepare:
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
      assembly_version: ${{ steps.version.outputs.assembly_version }}
      informational_version: ${{ steps.version.outputs.informational_version }}
      tag: ${{ steps.version.outputs.tag }}
      checkout_ref: ${{ steps.version.outputs.checkout_ref }}
    
    steps:
      - name: Get release info
        id: version
        run: |
          if [[ "${{ github.event_name }}" == "push" ]]; then
            TAG="${GITHUB_REF#refs/tags/}"
            CHECKOUT_REF="${GITHUB_REF}"
          else
            RAW_TAG="${{ github.event.inputs.tag }}"
            if [[ "${RAW_TAG}" == refs/tags/* ]]; then
              TAG="${RAW_TAG#refs/tags/}"
            elif [[ "${RAW_TAG}" == v* ]]; then
              TAG="${RAW_TAG}"
            else
              TAG="v${RAW_TAG}"
            fi
            CHECKOUT_REF="${GITHUB_SHA}"
          fi
          VERSION="${TAG#v}"
          IFS='.' read -r -a VERSION_PARTS <<< "${VERSION}"
          while [ "${#VERSION_PARTS[@]}" -lt 4 ]; do
            VERSION_PARTS+=("0")
          done
          ASSEMBLY_VERSION="${VERSION_PARTS[0]}.${VERSION_PARTS[1]}.${VERSION_PARTS[2]}.${VERSION_PARTS[3]}"
          echo "tag=${TAG}" >> $GITHUB_OUTPUT
          echo "version=${VERSION}" >> $GITHUB_OUTPUT
          echo "assembly_version=${ASSEMBLY_VERSION}" >> $GITHUB_OUTPUT
          echo "informational_version=${VERSION}" >> $GITHUB_OUTPUT
          echo "checkout_ref=${CHECKOUT_REF}" >> $GITHUB_OUTPUT

  build-windows:
    needs: prepare
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        arch: [x64, x86]
    name: Build_Windows_${{ matrix.arch }}
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: recursive
          ref: ${{ needs.prepare.outputs.checkout_ref }}

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: Restore
        run: dotnet restore ${{ env.Solution_Name }}

      - name: Build
        run: >
          dotnet build ${{ env.Solution_Name }} -c Release --no-restore -v minimal
          -p:Version=${{ needs.prepare.outputs.version }}
          -p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }}
          -p:FileVersion=${{ needs.prepare.outputs.assembly_version }}
          -p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}

      - name: Publish
        run: |
          dotnet publish LanMountainDesktop/LanMountainDesktop.csproj `
            -c Release `
            -o ./publish/windows-${{ matrix.arch }} `
            --self-contained `
            -r win-${{ matrix.arch }} `
            -p:PublishSingleFile=false `
            -p:SelfContained=true `
            -p:DebugType=none `
            -p:DebugSymbols=false `
            -p:PublishTrimmed=false `
            -p:PublishReadyToRun=false `
            -p:Version=${{ needs.prepare.outputs.version }} `
            -p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }} `
            -p:FileVersion=${{ needs.prepare.outputs.assembly_version }} `
            -p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}
        shell: pwsh

      - name: Install Inno Setup
        run: choco install innosetup -y --no-progress
        shell: pwsh

      - name: Build Installer
        run: |
          $version = "${{ needs.prepare.outputs.version }}"
          $arch = "${{ matrix.arch }}"
          $publishDir = "publish\windows-$arch"
          $installerScript = "LanMountainDesktop\installer\LanMountainDesktop.iss"
          $outputDir = "build-installer"
          
          # Verify source directory exists
          if (-not (Test-Path -Path $publishDir)) {
            Write-Error "Publish directory not found: $publishDir"
            Get-ChildItem -Path "publish" -Directory -ErrorAction SilentlyContinue | Select-Object Name
            exit 1
          }
          
          # Create output directory
          New-Item -ItemType Directory -Path $outputDir -Force | Out-Null
          
          # Verify installer script exists
          if (-not (Test-Path -Path $installerScript)) {
            Write-Error "Installer script not found: $installerScript"
            exit 1
          }
          
          # Find Inno Setup compiler (choco may install a shim in PATH)
          $isccPath = $null
          $isccCommand = Get-Command ISCC.exe -ErrorAction SilentlyContinue
          if ($isccCommand) {
            $isccPath = $isccCommand.Source
          }

          $candidatePaths = @(
            "C:\Program Files (x86)\Inno Setup 6\ISCC.exe",
            "C:\Program Files\Inno Setup 6\ISCC.exe",
            "$env:ChocolateyInstall\bin\ISCC.exe",
            "$env:ChocolateyInstall\lib\innosetup\tools\ISCC.exe"
          )

          if (-not $isccPath) {
            foreach ($candidate in $candidatePaths) {
              if ($candidate -and (Test-Path -Path $candidate)) {
                $isccPath = $candidate
                break
              }
            }
          }

          if (-not $isccPath) {
            Write-Host "ISCC.exe was not found in PATH or known locations."
            Write-Host "Checked locations:"
            $candidatePaths | ForEach-Object { Write-Host " - $_" }
            Write-Host "Chocolatey bin listing (if exists):"
            Get-ChildItem "$env:ChocolateyInstall\bin" -Filter "*iscc*" -ErrorAction SilentlyContinue | Select-Object FullName
            Write-Error "Inno Setup compiler not found."
            exit 1
          }
          
          Write-Host "Found Inno Setup at: $isccPath"
          
          # Build installer with iscc.exe
          Write-Host "Building installer for Windows $arch with version $version..."
          
          $publishDir = (Resolve-Path $publishDir).Path
          $outputDir = (Resolve-Path $outputDir).Path
          $installerScript = (Resolve-Path $installerScript).Path

          $compileArgs = @(
            "/DMyAppVersion=$version",
            "/DPublishDir=$publishDir",
            "/DMyOutputDir=$outputDir",
            "/DMyAppArch=$arch",
            $installerScript
          )
          
          Write-Host "Compile command: `"$isccPath`" $($compileArgs -join ' ')"
          
          # Execute the compiler
          & $isccPath @compileArgs
          if ($LASTEXITCODE -ne 0) {
            Write-Error "Inno Setup compiler exited with code $LASTEXITCODE"
            exit 1
          }
          
          # Check if build was successful
          $installerFile = Get-ChildItem -Path $outputDir -Filter "*.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
          if (-not $installerFile) {
            Write-Error "Failed to create installer"
            exit 1
          }
          
          Write-Host "✅ Successfully created: $($installerFile.Name)"
          Write-Host "Installer size: $([Math]::Round($installerFile.Length / 1MB, 2)) MB"
        shell: pwsh

      - name: Upload Installer
        uses: actions/upload-artifact@v4
        with:
          name: release-windows-${{ matrix.arch }}
          path: build-installer/*.exe
          if-no-files-found: error
          retention-days: 30

  build-linux:
    needs: prepare
    runs-on: ubuntu-latest
    name: Build_Linux
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: recursive
          ref: ${{ needs.prepare.outputs.checkout_ref }}

      - name: Install dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y \
            libfontconfig1 libfreetype6 \
            libx11-6 libxrandr2 libxinerama1 \
            libxi6 libxcursor1 libxext6 \
            libxrender1 libxkbcommon-x11-0

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: Restore
        run: dotnet restore ${{ env.Solution_Name }}

      - name: Build
        run: >
          dotnet build ${{ env.Solution_Name }} -c Release --no-restore -v minimal
          -p:Version=${{ needs.prepare.outputs.version }}
          -p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }}
          -p:FileVersion=${{ needs.prepare.outputs.assembly_version }}
          -p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}

      - name: Publish
        run: |
          dotnet publish LanMountainDesktop/LanMountainDesktop.csproj \
            -c Release \
            -o ./publish/linux-x64 \
            --self-contained \
            -r linux-x64 \
            -p:PublishSingleFile=false \
            -p:SelfContained=true \
            -p:DebugType=none \
            -p:DebugSymbols=false \
            -p:PublishTrimmed=false \
            -p:PublishReadyToRun=false \
            -p:Version=${{ needs.prepare.outputs.version }} \
            -p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }} \
            -p:FileVersion=${{ needs.prepare.outputs.assembly_version }} \
            -p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}

      - name: Package as DEB
        run: |
          version="${{ needs.prepare.outputs.version }}"
          source="publish/linux-x64"
          package_name="LanMountainDesktop"
          package_version="${version}"
          arch="amd64"
          desktop_template="LanMountainDesktop/packaging/linux/LanMountainDesktop.desktop"
          icon_source="LanMountainDesktop/packaging/linux/lanmountaindesktop.png"
          
          # Verify source directory exists
          if [ ! -d "$source" ]; then
            echo "Error: Source directory not found: $source"
            ls -la publish/ || echo "publish directory not found"
            exit 1
          fi
          
          # Create DEB package structure
          mkdir -p "build-deb/DEBIAN"
          mkdir -p "build-deb/usr/local/bin"
          mkdir -p "build-deb/usr/share/applications"
          mkdir -p "build-deb/usr/share/pixmaps"
          mkdir -p "build-deb/usr/share/icons/hicolor/256x256/apps"
          
          # Copy application files
          cp -r "$source"/* "build-deb/usr/local/bin/"
          
          # Verify copy was successful
          item_count=$(find build-deb/usr/local/bin -type f 2>/dev/null | wc -l)
          echo "DEB package contains $item_count files"
          
          if [ "$item_count" -eq 0 ]; then
            echo "Error: DEB package is empty after copy"
            exit 1
          fi

          if [ ! -f "$desktop_template" ] || [ ! -f "$icon_source" ]; then
            echo "Error: Linux desktop resources are missing"
            ls -la "LanMountainDesktop/packaging/linux" || true
            exit 1
          fi

          sed \
            -e "s|@@EXEC@@|/usr/local/bin/LanMountainDesktop|g" \
            -e "s|@@ICON@@|lanmountaindesktop|g" \
            "$desktop_template" > "build-deb/usr/share/applications/LanMountainDesktop.desktop"

          cp "$icon_source" "build-deb/usr/share/pixmaps/lanmountaindesktop.png"
          cp "$icon_source" "build-deb/usr/share/icons/hicolor/256x256/apps/lanmountaindesktop.png"

          {
            printf '%s\n' '#!/bin/sh'
            printf '%s\n' 'set -e'
            printf '%s\n' 'if command -v update-desktop-database >/dev/null 2>&1; then'
            printf '%s\n' '  update-desktop-database /usr/share/applications >/dev/null 2>&1 || true'
            printf '%s\n' 'fi'
            printf '%s\n' 'if command -v gtk-update-icon-cache >/dev/null 2>&1; then'
            printf '%s\n' '  gtk-update-icon-cache /usr/share/icons/hicolor >/dev/null 2>&1 || true'
            printf '%s\n' 'fi'
          } > "build-deb/DEBIAN/postinst"
          
          # Create control file (NOTE: No leading spaces in control file)
          {
            printf '%s\n' "Package: $package_name"
            printf '%s\n' "Version: $package_version"
            printf '%s\n' "Architecture: $arch"
            printf '%s\n' "Maintainer: LanMountain Team <dev@example.com>"
            printf '%s\n' "Description: LanMountain Desktop Application"
            printf '%s\n' " A desktop application for LanMountain."
          } > "build-deb/DEBIAN/control"
          
          # Set proper permissions
          chmod 755 "build-deb/usr/local/bin/LanMountainDesktop" || chmod 755 "build-deb/usr/local/bin"/*
          chmod 644 "build-deb/usr/share/applications/LanMountainDesktop.desktop"
          chmod 644 "build-deb/usr/share/pixmaps/lanmountaindesktop.png"
          chmod 644 "build-deb/usr/share/icons/hicolor/256x256/apps/lanmountaindesktop.png"
          chmod 755 "build-deb/DEBIAN/postinst"
          
          # Create DEB file
          if dpkg-deb --build "build-deb" "${package_name}_${package_version}_${arch}.deb"; then
            echo "Successfully created: ${package_name}_${package_version}_${arch}.deb"
            ls -lh "${package_name}_${package_version}_${arch}.deb"
          else
            echo "Error: Failed to build DEB package"
            exit 1
          fi

      - name: Upload
        uses: actions/upload-artifact@v4
        with:
          name: release-linux
          path: "*.deb"
          if-no-files-found: error
          retention-days: 30

  build-macos:
    needs: prepare
    runs-on: macos-latest
    strategy:
      matrix:
        arch: [x64, arm64]
    name: Build_macOS_${{ matrix.arch }}
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
          submodules: recursive
          ref: ${{ needs.prepare.outputs.checkout_ref }}

      - name: Setup .NET
        uses: actions/setup-dotnet@v4
        with:
          dotnet-version: ${{ env.DOTNET_VERSION }}

      - name: Restore
        run: dotnet restore ${{ env.Solution_Name }}

      - name: Build
        run: >
          dotnet build ${{ env.Solution_Name }} -c Release --no-restore -v minimal
          -p:Version=${{ needs.prepare.outputs.version }}
          -p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }}
          -p:FileVersion=${{ needs.prepare.outputs.assembly_version }}
          -p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}

      - name: Publish
        run: |
          dotnet publish LanMountainDesktop/LanMountainDesktop.csproj \
            -c Release \
            -o ./publish/macos-${{ matrix.arch }} \
            --self-contained \
            -r osx-${{ matrix.arch }} \
            -p:PublishSingleFile=false \
            -p:SelfContained=true \
            -p:DebugType=none \
            -p:DebugSymbols=false \
            -p:PublishTrimmed=false \
            -p:PublishReadyToRun=false \
            -p:Version=${{ needs.prepare.outputs.version }} \
            -p:AssemblyVersion=${{ needs.prepare.outputs.assembly_version }} \
            -p:FileVersion=${{ needs.prepare.outputs.assembly_version }} \
            -p:InformationalVersion=${{ needs.prepare.outputs.informational_version }}

      - name: Package as DMG
        run: |
          version="${{ needs.prepare.outputs.version }}"
          arch="${{ matrix.arch }}"
          source="publish/macos-$arch"
          app_name="LanMountainDesktop"
          package_name="${app_name}-${version}-macos-${arch}"
          
          # Verify source directory exists
          if [ ! -d "$source" ]; then
            echo "Error: Source directory not found: $source"
            ls -la publish/ || echo "publish directory not found"
            exit 1
          fi
          
          # Create app bundle structure
          mkdir -p "${app_name}.app/Contents/MacOS"
          mkdir -p "${app_name}.app/Contents/Resources"
          
          # Copy application files
          cp -r "$source"/* "${app_name}.app/Contents/MacOS/"
          
          # Verify copy was successful
          item_count=$(find "${app_name}.app/Contents/MacOS" -type f | wc -l)
          echo "App bundle contains $item_count files"
          
          if [ "$item_count" -eq 0 ]; then
            echo "Error: App bundle is empty after copy"
            exit 1
          fi

          # Create Info.plist
          {
            printf '%s\n' '<?xml version="1.0" encoding="UTF-8"?>'
            printf '%s\n' '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">'
            printf '%s\n' '<plist version="1.0">'
            printf '%s\n' '<dict>'
            printf '%s\n' '  <key>CFBundleExecutable</key>'
            printf '%s\n' '  <string>LanMountainDesktop</string>'
            printf '%s\n' '  <key>CFBundleName</key>'
            printf '%s\n' '  <string>LanMountain Desktop</string>'
            printf '%s\n' '  <key>CFBundleVersion</key>'
            printf '%s\n' "  <string>$version</string>"
            printf '%s\n' '  <key>CFBundleShortVersionString</key>'
            printf '%s\n' "  <string>$version</string>"
            printf '%s\n' '  <key>CFBundleIdentifier</key>'
            printf '%s\n' '  <string>com.lanmountain.desktop</string>'
            printf '%s\n' '  <key>CFBundlePackageType</key>'
            printf '%s\n' '  <string>APPL</string>'
            printf '%s\n' '</dict>'
            printf '%s\n' '</plist>'
          } > "${app_name}.app/Contents/Info.plist"
          
          # Create DMG
          mkdir -p dmg-temp
          cp -r "${app_name}.app" dmg-temp/
          
          if hdiutil create -volname "${app_name}" -srcfolder dmg-temp -ov -format UDZO "${package_name}.dmg" 2>&1; then
            echo "Successfully created: ${package_name}.dmg"
            ls -lh "${package_name}.dmg"
          else
            echo "Error: Failed to create DMG"
            exit 1
          fi
          
          # Cleanup
          rm -rf dmg-temp "${app_name}.app"

      - name: Upload
        uses: actions/upload-artifact@v4
        with:
          name: release-macos-${{ matrix.arch }}
          path: "*.dmg"
          if-no-files-found: error
          retention-days: 30

  github-release:
    needs: [ prepare, build-windows, build-linux, build-macos ]
    runs-on: ubuntu-latest
    permissions:
      contents: write
    
    steps:
      - name: Download artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts
          pattern: release-*

      - name: List artifacts structure
        run: |
          echo "🔍 Artifact directory structure:"
          find artifacts -type f -o -type d | sort
          echo ""
          echo "📊 Files found:"
          find artifacts -type f -exec ls -lh {} \;
          echo ""
          echo "📁 Full tree:"
          tree artifacts || find artifacts -print | sed -e 's;[^/]*/;|____;g;s;____|; |;g'

      - name: Flatten artifacts for release
        run: |
          echo "📦 Organizing artifacts..."
          mkdir -p release-files
          find artifacts -type f \( -name "*.exe" -o -name "*.deb" -o -name "*.dmg" \) -exec cp -v {} release-files/ \;
          echo ""
          echo "✅ Files ready for release:"
          ls -lh release-files/ || echo "⚠️ No files found in release-files"
          echo ""
          echo "📋 Total files:"
          file_count=$(find release-files -type f | wc -l)
          echo "$file_count"
          if [ "$file_count" -eq 0 ]; then
            echo "Error: No installer/package files found for release"
            exit 1
          fi

      - name: Create Release
        uses: ncipollo/release-action@v1
        with:
          tag: ${{ needs.prepare.outputs.tag }}
          name: ${{ needs.prepare.outputs.tag }}
          commit: ${{ github.sha }}
          allowUpdates: true
          draft: false
          prerelease: ${{ github.event.inputs.is_prerelease == 'true' }}
          artifacts: "release-files/**"
          body: |
            ## Release ${{ needs.prepare.outputs.version }}
            
            ### Windows
            - **LanMountainDesktop-Setup-{version}-x64.exe** - 64-bit installer
            - **LanMountainDesktop-Setup-{version}-x86.exe** - 32-bit installer
            
            Installation: Double-click the .exe file and follow the wizard.
            
            ### Linux
            - **LanMountainDesktop-{version}-linux-x64.deb** - Debian package (x64)
            
            ### macOS
            - **LanMountainDesktop-{version}-macos-x64.dmg** - Intel processor
            - **LanMountainDesktop-{version}-macos-arm64.dmg** - Apple Silicon (M1/M2/M3)
            
            See commits for changes.
          token: ${{ secrets.GITHUB_TOKEN }}
