# Release build: tag push → build wheel + OCI → push to GHCR → create GitHub release
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: styrened-release-build
  namespace: argo
spec:
  arguments:
    parameters:
      - name: ref          # refs/tags/v0.4.0
      - name: commit-sha
      - name: repo
        value: styrene-lab/styrened
  entrypoint: pipeline
  serviceAccountName: ci-workflow-sa

  hooks:
    exit:
      template: notify-release-result

  volumeClaimTemplates:
    - metadata:
        name: workspace-pypi
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: local-path
        resources:
          requests:
            storage: 5Gi
    - metadata:
        name: workspace-oci
      spec:
        accessModes: ["ReadWriteOnce"]
        storageClassName: local-path
        resources:
          requests:
            storage: 10Gi

  volumes:
    - name: ghcr-auth
      secret:
        secretName: ghcr-secret
    - name: pypi-auth
      secret:
        secretName: pypi-secret
    - name: cachix-auth
      secret:
        secretName: cachix-auth-token
    - name: version-scratch
      emptyDir: {}
    - name: ntfy-auth
      secret:
        secretName: ntfy-secret

  templates:
    - name: pipeline
      dag:
        tasks:
          - name: extract-version
            template: parse-version
          - name: checkout-pypi
            template: git-checkout-pypi
          - name: checkout-oci
            template: git-checkout-oci
          - name: build-wheel
            template: build-wheel
            depends: "checkout-pypi"
          - name: build-oci
            template: nix-build-oci
            depends: "checkout-oci"
          - name: publish-pypi
            template: publish-pypi
            depends: "build-wheel && extract-version"
            arguments:
              parameters:
                - name: version
                  value: "{{tasks.extract-version.outputs.parameters.version}}"
          - name: push-oci
            template: push-ghcr-release
            depends: "build-oci && extract-version"
            arguments:
              parameters:
                - name: version
                  value: "{{tasks.extract-version.outputs.parameters.version}}"
                - name: prerelease
                  value: "{{tasks.extract-version.outputs.parameters.prerelease}}"
          - name: create-release
            template: github-release
            depends: "push-oci && publish-pypi"
            arguments:
              parameters:
                - name: version
                  value: "{{tasks.extract-version.outputs.parameters.version}}"
                - name: prerelease
                  value: "{{tasks.extract-version.outputs.parameters.prerelease}}"
          - name: notify-meta-package
            template: dispatch-styrene-pypi
            depends: "create-release"
            when: "'{{tasks.extract-version.outputs.parameters.prerelease}}' == 'false'"
            arguments:
              parameters:
                - name: version
                  value: "{{tasks.extract-version.outputs.parameters.version}}"

    - name: parse-version
      container:
        image: alpine:latest
        command: [sh, -c]
        args:
          - |
            set -euo pipefail
            REF="{{workflow.parameters.ref}}"
            VERSION="${REF#refs/tags/v}"
            echo "$VERSION" > /scratch/version
            # Detect prerelease
            if echo "$VERSION" | grep -qE '(rc|alpha|beta|dev)'; then
              echo "true" > /scratch/prerelease
            else
              echo "false" > /scratch/prerelease
            fi
            echo "Version: $VERSION, Prerelease: $(cat /scratch/prerelease)"
        volumeMounts:
          - name: version-scratch
            mountPath: /scratch
      outputs:
        parameters:
          - name: version
            valueFrom:
              path: /scratch/version
          - name: prerelease
            valueFrom:
              path: /scratch/prerelease

    - name: git-checkout-pypi
      container:
        image: alpine/git:latest
        command: [sh, -c]
        args:
          - |
            set -euo pipefail
            TOKEN=$(cat /ghcr/password)
            git clone \
              https://x-access-token:${TOKEN}@github.com/{{workflow.parameters.repo}}.git \
              /workspace/src
            cd /workspace/src
            git checkout {{workflow.parameters.commit-sha}}
        volumeMounts:
          - name: workspace-pypi
            mountPath: /workspace
          - name: ghcr-auth
            mountPath: /ghcr
            readOnly: true
        resources:
          requests:
            cpu: 100m
            memory: 128Mi

    - name: git-checkout-oci
      container:
        image: alpine/git:latest
        command: [sh, -c]
        args:
          - |
            set -euo pipefail
            TOKEN=$(cat /ghcr/password)
            git clone \
              https://x-access-token:${TOKEN}@github.com/{{workflow.parameters.repo}}.git \
              /workspace/src
            cd /workspace/src
            git checkout {{workflow.parameters.commit-sha}}
        volumeMounts:
          - name: workspace-oci
            mountPath: /workspace
          - name: ghcr-auth
            mountPath: /ghcr
            readOnly: true
        resources:
          requests:
            cpu: 100m
            memory: 128Mi

    - name: build-wheel
      container:
        image: python:3.11-slim
        command: [sh, -c]
        args:
          - |
            set -euo pipefail
            pip install --quiet build
            cd /workspace/src
            python -m build --wheel --sdist -o /workspace/dist/
            ls -la /workspace/dist/
        volumeMounts:
          - name: workspace-pypi
            mountPath: /workspace
        resources:
          requests:
            cpu: 500m
            memory: 512Mi

    - name: publish-pypi
      inputs:
        parameters:
          - name: version
      container:
        image: python:3.11-slim
        command: [sh, -c]
        args:
          - |
            set -euo pipefail
            pip install --quiet twine
            VERSION="{{inputs.parameters.version}}"
            echo "Publishing styrened ${VERSION} to PyPI..."
            ls -la /workspace/dist/
            TWINE_USERNAME=__token__ \
            TWINE_PASSWORD=$(cat /pypi/token) \
            twine upload --skip-existing /workspace/dist/styrened-${VERSION}*
            echo "Published to PyPI"
        volumeMounts:
          - name: workspace-pypi
            mountPath: /workspace
          - name: pypi-auth
            mountPath: /pypi
            readOnly: true
        resources:
          requests:
            cpu: 100m
            memory: 128Mi

    - name: nix-build-oci
      container:
        image: nixos/nix:latest
        command: ["/bin/sh", "-c"]
        env:
          - name: PATH
            value: "/root/.nix-profile/bin:/nix/var/nix/profiles/default/bin:/bin:/usr/bin"
        args:
          - |
            set -euo pipefail
            mkdir -p /etc/nix
            echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf
            echo "sandbox = false" >> /etc/nix/nix.conf
            echo "max-jobs = auto" >> /etc/nix/nix.conf
            echo "cores = 0" >> /etc/nix/nix.conf

            # Configure Cachix for faster builds
            nix-env -iA cachix -f https://cachix.org/api/v1/install
            export CACHIX_AUTH_TOKEN=$(cat /cachix/token)
            cachix use styrene

            cd /workspace/src
            nix build .#oci --no-link --print-out-paths > /workspace/oci-path
            echo "Built: $(cat /workspace/oci-path)"

            # Push build results to Cachix for future runs
            cachix push styrene $(cat /workspace/oci-path)
        volumeMounts:
          - name: workspace-oci
            mountPath: /workspace
          - name: cachix-auth
            mountPath: /cachix
            readOnly: true
        resources:
          requests:
            cpu: "4"
            memory: 8Gi
          limits:
            cpu: "16"
            memory: 32Gi

    - name: push-ghcr-release
      inputs:
        parameters:
          - name: version
          - name: prerelease
      container:
        image: nixos/nix:latest
        command: ["/bin/sh", "-c"]
        env:
          - name: PATH
            value: "/root/.nix-profile/bin:/nix/var/nix/profiles/default/bin:/bin:/usr/bin"
        args:
          - |
            set -euo pipefail
            mkdir -p /etc/nix
            echo "experimental-features = nix-command flakes" >> /etc/nix/nix.conf
            echo "sandbox = false" >> /etc/nix/nix.conf

            # Configure Cachix
            nix-env -iA cachix -f https://cachix.org/api/v1/install
            export CACHIX_AUTH_TOKEN=$(cat /cachix/token)
            cachix use styrene

            cd /workspace/src
            VERSION="{{inputs.parameters.version}}"
            PRERELEASE="{{inputs.parameters.prerelease}}"
            SHORT_SHA=$(echo "{{workflow.parameters.commit-sha}}" | cut -c1-7)

            # Auth
            mkdir -p ~/.docker
            GHCR_USER=$(cat /ghcr/username 2>/dev/null || echo "styrene-lab")
            GHCR_TOKEN=$(cat /ghcr/password)
            echo "{\"auths\":{\"ghcr.io\":{\"auth\":\"$(echo -n "${GHCR_USER}:${GHCR_TOKEN}" | base64)\"}}}" > ~/.docker/config.json

            # Trust policy for skopeo (nixos/nix image lacks this)
            mkdir -p /etc/containers
            echo '{"default":[{"type":"insecureAcceptAnything"}]}' > /etc/containers/policy.json

            # Push version tag via nix2container
            nix run .#oci.copyToRegistry

            # Additional tags via skopeo
            nix-env -iA nixpkgs.skopeo 2>/dev/null || true
            skopeo copy --authfile ~/.docker/config.json \
              docker://ghcr.io/styrene-lab/styrened:${VERSION} \
              docker://ghcr.io/styrene-lab/styrened:${SHORT_SHA}

            # Only tag latest for stable releases
            if [ "$PRERELEASE" = "false" ]; then
              skopeo copy --authfile ~/.docker/config.json \
                docker://ghcr.io/styrene-lab/styrened:${VERSION} \
                docker://ghcr.io/styrene-lab/styrened:latest
              echo "Tagged: ${VERSION}, ${SHORT_SHA}, latest"
            else
              echo "Tagged: ${VERSION}, ${SHORT_SHA} (prerelease, no latest)"
            fi
        volumeMounts:
          - name: workspace-oci
            mountPath: /workspace
          - name: cachix-auth
            mountPath: /cachix
            readOnly: true
          - name: ghcr-auth
            mountPath: /ghcr
            readOnly: true
        resources:
          requests:
            cpu: 500m
            memory: 1Gi

    - name: github-release
      inputs:
        parameters:
          - name: version
          - name: prerelease
      container:
        image: alpine:latest
        command: [sh, -c]
        args:
          - |
            set -euo pipefail
            apk add --no-cache curl jq tar gzip

            VERSION="{{inputs.parameters.version}}"
            PRERELEASE="{{inputs.parameters.prerelease}}"
            GHCR_TOKEN=$(cat /ghcr/password)

            cd /workspace/src

            # Generate changelog from last tag
            PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "")
            if [ -n "$PREV_TAG" ]; then
              CHANGELOG=$(git log ${PREV_TAG}..HEAD --oneline --no-merges | sed 's/^/- /')
            else
              CHANGELOG="Initial release"
            fi

            # Create source archive
            tar czf /workspace/dist/styrened-${VERSION}.tar.gz -C /workspace/src .

            # Create release via GitHub API
            RELEASE_DATA=$(jq -n \
              --arg tag "v${VERSION}" \
              --arg name "v${VERSION}" \
              --arg body "## Changes\n\n${CHANGELOG}\n\n## Container Image\n\n\`\`\`bash\ndocker pull ghcr.io/styrene-lab/styrened:${VERSION}\n\`\`\`" \
              --argjson prerelease "${PRERELEASE}" \
              '{tag_name: $tag, name: $name, body: $body, prerelease: $prerelease}')

            RELEASE_ID=$(curl -sf -X POST \
              -H "Authorization: token ${GHCR_TOKEN}" \
              -H "Accept: application/vnd.github+json" \
              "https://api.github.com/repos/{{workflow.parameters.repo}}/releases" \
              -d "$RELEASE_DATA" | jq -r '.id')

            echo "Created release ID: ${RELEASE_ID}"

            # Upload wheel artifact
            for f in /workspace/dist/styrened-*.whl /workspace/dist/styrened-*.tar.gz; do
              [ -f "$f" ] || continue
              BASENAME=$(basename "$f")
              echo "Uploading ${BASENAME}..."
              curl -sf -X POST \
                -H "Authorization: token ${GHCR_TOKEN}" \
                -H "Content-Type: application/octet-stream" \
                "https://uploads.github.com/repos/{{workflow.parameters.repo}}/releases/${RELEASE_ID}/assets?name=${BASENAME}" \
                --data-binary "@${f}"
            done
            echo "Release v${VERSION} published"
        volumeMounts:
          - name: workspace-pypi
            mountPath: /workspace
          - name: ghcr-auth
            mountPath: /ghcr
            readOnly: true
        resources:
          requests:
            cpu: 100m
            memory: 128Mi

    - name: dispatch-styrene-pypi
      inputs:
        parameters:
          - name: version
      container:
        image: alpine:latest
        command: [sh, -c]
        args:
          - |
            set -euo pipefail
            apk add --no-cache curl >/dev/null 2>&1

            VERSION="{{inputs.parameters.version}}"
            GHCR_TOKEN=$(cat /ghcr/password)

            echo "Dispatching styrened-release to styrene-pypi (version ${VERSION})..."
            HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
              -H "Authorization: token ${GHCR_TOKEN}" \
              -H "Accept: application/vnd.github+json" \
              "https://api.github.com/repos/styrene-lab/styrene-pypi/dispatches" \
              -d "{\"event_type\":\"styrened-release\",\"client_payload\":{\"version\":\"${VERSION}\"}}")

            if [ "$HTTP_CODE" = "204" ]; then
              echo "Dispatch successful"
            else
              echo "Warning: dispatch returned HTTP ${HTTP_CODE} (non-fatal)"
            fi
        volumeMounts:
          - name: ghcr-auth
            mountPath: /ghcr
            readOnly: true
        resources:
          requests:
            cpu: 100m
            memory: 64Mi

    - name: notify-release-result
      container:
        image: curlimages/curl:latest
        command: [sh, -c]
        args:
          - |
            NTFY_TOKEN=$(cat /ntfy/token)
            REF="{{workflow.parameters.ref}}"
            VERSION="${REF#refs/tags/v}"
            ARGO_URL="https://argo.vanderlyn.house/workflows/argo/{{workflow.name}}"
            if [ "{{workflow.status}}" = "Succeeded" ]; then
              curl -sf \
                -H "Authorization: Bearer ${NTFY_TOKEN}" \
                -H "Title: Released v${VERSION}" \
                -H "Priority: 3" \
                -H "Tags: rocket" \
                -H "Click: ${ARGO_URL}" \
                -d "styrened v${VERSION} published to PyPI + GHCR" \
                http://ntfy.ntfy.svc.cluster.local/styrene-ci || true
            else
              curl -sf \
                -H "Authorization: Bearer ${NTFY_TOKEN}" \
                -H "Title: Release FAILED: v${VERSION}" \
                -H "Priority: 5" \
                -H "Tags: rotating_light" \
                -H "Click: ${ARGO_URL}" \
                -d "Release pipeline failed — check Argo for details" \
                http://ntfy.ntfy.svc.cluster.local/styrene-ci || true
            fi
        volumeMounts:
          - name: ntfy-auth
            mountPath: /ntfy
            readOnly: true
        resources:
          requests:
            cpu: 50m
            memory: 32Mi
