# Install Packs Workflow
# Complete workflow for installing packs from multiple sources with dependency resolution

name: install_packs
ref: core.install_packs
label: "Install Packs"
description: "Install one or more packs from git repositories, HTTP archives, or pack registry with automatic dependency resolution"
version: "1.0.0"

# Input parameters (StackStorm-style with inline required/secret)
parameters:
  packs:
    type: array
    description: "List of packs to install (git URLs, HTTP URLs, or pack refs like 'slack@1.0.0')"
    items:
      type: string
    minItems: 1
    required: true
  ref_spec:
    type: string
    description: "Git reference to checkout for git URLs (branch, tag, or commit)"
  skip_dependencies:
    type: boolean
    description: "Skip installing pack dependencies"
    default: false
  skip_tests:
    type: boolean
    description: "Skip running pack tests before registration"
    default: false
  skip_env_build:
    type: boolean
    description: "Skip building runtime environments (Python/Node.js)"
    default: false
  force:
    type: boolean
    description: "Force installation even if packs already exist or tests fail"
    default: false
  registry_url:
    type: string
    description: "Pack registry URL for resolving pack refs"
    default: "https://registry.attune.io/index.json"
  packs_base_dir:
    type: string
    description: "Base directory for permanent pack storage"
    default: "/opt/attune/packs"
  api_url:
    type: string
    description: "Attune API URL"
    default: "http://localhost:8080"
  timeout:
    type: integer
    description: "Timeout in seconds for the entire workflow"
    default: 1800
    minimum: 300
    maximum: 7200

# Workflow variables
vars:
  - temp_dir: null
  - downloaded_packs: []
  - missing_dependencies: []
  - installed_pack_refs: []
  - failed_packs: []
  - start_time: null

# Workflow tasks
tasks:
  # Task 1: Initialize workflow
  - name: initialize
    action: core.noop
    input:
      message: "Starting pack installation workflow"
    publish:
      - start_time: "{{ now() }}"
      - temp_dir: "/tmp/attune-pack-install-{{ uuid() }}"
    on_success: download_packs

  # Task 2: Download packs from specified sources
  - name: download_packs
    action: core.download_packs
    input:
      packs: "{{ parameters.packs }}"
      destination_dir: "{{ workflow.temp_dir }}"
      registry_url: "{{ parameters.registry_url }}"
      ref_spec: "{{ parameters.ref_spec }}"
      api_url: "{{ parameters.api_url }}"
      timeout: 300
      verify_ssl: true
    publish:
      - downloaded_packs: "{{ task.download_packs.result.downloaded_packs }}"
      - failed_packs: "{{ task.download_packs.result.failed_packs }}"
    on_success:
      - when: "{{ task.download_packs.result.success_count > 0 }}"
        do: check_download_results
    on_failure: cleanup_on_failure

  # Task 3: Check if any packs were successfully downloaded
  - name: check_download_results
    action: core.noop
    input:
      message: "Downloaded {{ task.download_packs.result.success_count }} pack(s)"
    on_success:
      - when: "{{ not parameters.skip_dependencies }}"
        do: get_dependencies
      - when: "{{ parameters.skip_dependencies }}"
        do: build_environments

  # Task 4: Get pack dependencies from pack.yaml files
  - name: get_dependencies
    action: core.get_pack_dependencies
    input:
      pack_paths: "{{ workflow.downloaded_packs | map(attribute='pack_path') | list }}"
      api_url: "{{ parameters.api_url }}"
      skip_validation: false
    publish:
      - missing_dependencies: "{{ task.get_dependencies.result.missing_dependencies }}"
    on_success:
      - when: "{{ task.get_dependencies.result.missing_dependencies | length > 0 }}"
        do: install_dependencies
      - when: "{{ task.get_dependencies.result.missing_dependencies | length == 0 }}"
        do: build_environments
    on_failure: cleanup_on_failure

  # Task 5: Recursively install missing pack dependencies
  - name: install_dependencies
    action: core.install_packs
    input:
      packs: "{{ workflow.missing_dependencies | map(attribute='pack_ref') | list }}"
      skip_dependencies: false
      skip_tests: "{{ parameters.skip_tests }}"
      skip_env_build: "{{ parameters.skip_env_build }}"
      force: "{{ parameters.force }}"
      registry_url: "{{ parameters.registry_url }}"
      packs_base_dir: "{{ parameters.packs_base_dir }}"
      api_url: "{{ parameters.api_url }}"
      timeout: 900
    publish:
      - installed_pack_refs: "{{ task.install_dependencies.result.registered_packs | map(attribute='pack_ref') | list }}"
    on_success: build_environments
    on_failure:
      - when: "{{ parameters.force }}"
        do: build_environments
      - when: "{{ not parameters.force }}"
        do: cleanup_on_failure

  # Task 6: Build runtime environments (Python virtualenvs, npm install)
  - name: build_environments
    action: core.build_pack_envs
    input:
      pack_paths: "{{ workflow.downloaded_packs | map(attribute='pack_path') | list }}"
      packs_base_dir: "{{ parameters.packs_base_dir }}"
      python_version: "3.11"
      nodejs_version: "20"
      skip_python: false
      skip_nodejs: false
      force_rebuild: "{{ parameters.force }}"
      timeout: 600
    on_success:
      - when: "{{ not parameters.skip_tests }}"
        do: run_tests
      - when: "{{ parameters.skip_tests }}"
        do: register_packs
    on_failure:
      - when: "{{ parameters.force or parameters.skip_env_build }}"
        do:
          - when: "{{ not parameters.skip_tests }}"
            next: run_tests
          - when: "{{ parameters.skip_tests }}"
            next: register_packs
      - when: "{{ not parameters.force and not parameters.skip_env_build }}"
        do: cleanup_on_failure

  # Task 7: Run pack tests to verify functionality
  - name: run_tests
    action: core.run_pack_tests
    input:
      pack_paths: "{{ workflow.downloaded_packs | map(attribute='pack_path') | list }}"
      timeout: 300
      fail_on_error: false
    on_success: register_packs
    on_failure:
      - when: "{{ parameters.force }}"
        do: register_packs
      - when: "{{ not parameters.force }}"
        do: cleanup_on_failure

  # Task 8: Register packs in database and copy to permanent storage
  - name: register_packs
    action: core.register_packs
    input:
      pack_paths: "{{ workflow.downloaded_packs | map(attribute='pack_path') | list }}"
      packs_base_dir: "{{ parameters.packs_base_dir }}"
      skip_validation: false
      skip_tests: "{{ parameters.skip_tests }}"
      force: "{{ parameters.force }}"
      api_url: "{{ parameters.api_url }}"
    on_success: cleanup_success
    on_failure: cleanup_on_failure

  # Task 9: Cleanup temporary directory on success
  - name: cleanup_success
    action: core.noop
    input:
      message: "Pack installation completed successfully. Cleaning up temporary directory: {{ workflow.temp_dir }}"
    publish:
      - cleanup_status: "success"

  # Task 10: Cleanup temporary directory on failure
  - name: cleanup_on_failure
    action: core.noop
    input:
      message: "Pack installation failed. Cleaning up temporary directory: {{ workflow.temp_dir }}"
    publish:
      - cleanup_status: "failed"

# Output schema
output_schema:
  registered_packs:
    type: array
    description: "Successfully registered packs"
    items:
      type: object
      properties:
        pack_ref:
          type: string
        pack_id:
          type: integer
        pack_version:
          type: string
        storage_path:
          type: string
        components_count:
          type: integer
  failed_packs:
    type: array
    description: "Packs that failed to install"
    items:
      type: object
      properties:
        source:
          type: string
        error:
          type: string
        stage:
          type: string
  installed_dependencies:
    type: array
    description: "Pack dependencies that were installed"
    items:
      type: string
  summary:
    type: object
    description: "Installation summary"
    properties:
      total_requested:
        type: integer
      success_count:
        type: integer
      failure_count:
        type: integer
      dependencies_installed:
        type: integer
      duration_seconds:
        type: integer

# Metadata
metadata:
  description: |
    This workflow orchestrates the complete pack installation process:

    1. Download Packs: Downloads packs from git repositories, HTTP archives, or pack registry
    2. Get Dependencies: Analyzes pack.yaml files to identify dependencies
    3. Install Dependencies: Recursively installs missing pack dependencies
    4. Build Environments: Creates Python virtualenvs, installs requirements.txt and package.json deps
    5. Run Tests: Executes pack test suites (if present and not skipped)
    6. Register Packs: Loads pack components into database and copies to permanent storage

    The workflow supports:
    - Multiple pack sources (git URLs, HTTP archives, pack refs)
    - Automatic dependency resolution (recursive)
    - Runtime environment setup (Python, Node.js)
    - Pack testing before registration
    - Force mode to override validation failures
    - Comprehensive error handling and cleanup

  examples:
    - name: "Install pack from git repository"
      input:
        packs:
          - "https://github.com/attune/pack-slack.git"
        ref_spec: "v1.0.0"
        skip_dependencies: false
        skip_tests: false
        force: false

    - name: "Install multiple packs from registry"
      input:
        packs:
          - "slack@1.0.0"
          - "aws@2.1.0"
          - "kubernetes@3.0.0"
        skip_dependencies: false
        skip_tests: false
        force: false

    - name: "Install pack with force mode (skip validations)"
      input:
        packs:
          - "https://github.com/myorg/pack-custom.git"
        ref_spec: "main"
        skip_dependencies: true
        skip_tests: true
        force: true

    - name: "Install from HTTP archive"
      input:
        packs:
          - "https://example.com/packs/custom-pack.tar.gz"
        skip_dependencies: false
        skip_tests: false
        force: false

  tags:
    - pack
    - installation
    - workflow
    - automation
    - dependencies
    - git
    - registry
