name: Manage release PR
on:
  workflow_dispatch:
  push:
    branches:
      - main

concurrency:
  group: ${{ github.workflow }}
  cancel-in-progress: true

permissions: {}

jobs:
  bump:
    runs-on: ubuntu-latest
    steps:
      - name: Generate a token
        id: generate-token
        uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
        with:
          app-id: ${{ secrets.PUSH_O_MATIC_APP_ID }}
          private-key: ${{ secrets.PUSH_O_MATIC_APP_KEY }}

      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          token: ${{ steps.generate-token.outputs.token }}
          persist-credentials: true
          ref: main

      - name: Install uv
        uses: astral-sh/setup-uv@eac588ad8def6316056a12d4907a9d4d84ff7a3b # v7.3.0

      - name: Setup pnpm
        uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 # v4.2.0

      - name: Setup Node
        uses: actions/setup-node@6044e13b5dc448c55e2357c09f80417699197238 # v6.2.0
        with:
          node-version-file: './server/.nvmrc'
          cache: 'pnpm'
          cache-dependency-path: '**/pnpm-lock.yaml'

      - name: Determine release type
        id: bump-type
        uses: ietf-tools/semver-action@c90370b2958652d71c06a3484129a4d423a6d8a8 # v1.11.0
        with:
          token: ${{ steps.generate-token.outputs.token }}

      - name: Bump versions
        env:
          TYPE: ${{ steps.bump-type.outputs.bump }}
        run: |
          if [ "$TYPE" == "none" ]; then
            exit 1 # TODO: Is there a cleaner way to abort the workflow?
          fi
          misc/release/pump-version.sh -s $TYPE -m true

      - name: Manage Outline release document
        id: outline
        uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
        env:
          OUTLINE_API_KEY: ${{ secrets.OUTLINE_API_KEY }}
          NEXT_VERSION: ${{ steps.bump-type.outputs.next }}
        with:
          github-token: ${{ steps.generate-token.outputs.token }}
          script: |
            const fs = require('fs');

            const outlineKey = process.env.OUTLINE_API_KEY;
            const parentDocumentId = 'da856355-0844-43df-bd71-f8edce5382d9'
            const collectionId = 'e2910656-714c-4871-8721-447d9353bd73';
            const baseUrl = 'https://outline.immich.cloud';

            const listResponse = await fetch(`${baseUrl}/api/documents.list`, {
              method: 'POST',
              headers: {
                'Authorization': `Bearer ${outlineKey}`,
                'Content-Type': 'application/json'
              },
              body: JSON.stringify({ parentDocumentId })
            });

            if (!listResponse.ok) {
              throw new Error(`Outline list failed: ${listResponse.statusText}`);
            }

            const listData = await listResponse.json();
            const allDocuments = listData.data || [];

            const document = allDocuments.find(doc => doc.title === 'next');

            let documentId;
            let documentUrl;
            let documentText;

            if (!document) {
              // Create new document
              console.log('No existing document found. Creating new one...');
              const notesTmpl = fs.readFileSync('misc/release/notes.tmpl', 'utf8');
              const createResponse = await fetch(`${baseUrl}/api/documents.create`, {
                method: 'POST',
                headers: {
                  'Authorization': `Bearer ${outlineKey}`,
                  'Content-Type': 'application/json'
                },
                body: JSON.stringify({
                  title: 'next',
                  text: notesTmpl,
                  collectionId: collectionId,
                  parentDocumentId: parentDocumentId,
                  publish: true
                })
              });

              if (!createResponse.ok) {
                throw new Error(`Failed to create document: ${createResponse.statusText}`);
              }

              const createData = await createResponse.json();
              documentId = createData.data.id;
              const urlId = createData.data.urlId;
              documentUrl = `${baseUrl}/doc/next-${urlId}`;
              documentText = createData.data.text || '';
              console.log(`Created new document: ${documentUrl}`);
            } else {
              documentId = document.id;
              const docPath = document.url;
              documentUrl = `${baseUrl}${docPath}`;
              documentText = document.text || '';
              console.log(`Found existing document: ${documentUrl}`);
            }

            // Generate GitHub release notes
            console.log('Generating GitHub release notes...');
            const releaseNotesResponse = await github.rest.repos.generateReleaseNotes({
              owner: context.repo.owner,
              repo: context.repo.repo,
              tag_name: `${process.env.NEXT_VERSION}`,
            });

            // Combine the content
            const changelog = `
            # ${process.env.NEXT_VERSION}

            ${documentText}

            ${releaseNotesResponse.data.body}

            ---

            `

            const existingChangelog = fs.existsSync('CHANGELOG.md') ? fs.readFileSync('CHANGELOG.md', 'utf8') : '';
            fs.writeFileSync('CHANGELOG.md', changelog + existingChangelog, 'utf8');

            core.setOutput('document_url', documentUrl);

      - name: Create PR
        id: create-pr
        uses: peter-evans/create-pull-request@c0f553fe549906ede9cf27b5156039d195d2ece0 # v8.1.0
        with:
          token: ${{ steps.generate-token.outputs.token }}
          commit-message: 'chore: release ${{ steps.bump-type.outputs.next }}'
          title: 'chore: release ${{ steps.bump-type.outputs.next }}'
          body: 'Release notes: ${{ steps.outline.outputs.document_url }}'
          labels: 'changelog:skip'
          branch: 'release/next'
          draft: true
