#!/usr/bin/env bash
# Security SLSA Provenance - Execution Script
#
# This script generates and verifies SLSA provenance attestations.

set -euo pipefail

# Source helper scripts
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"

# shellcheck source=../scripts/_logging_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
# shellcheck source=../scripts/_error_handling_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
# shellcheck source=../scripts/_environment_helpers.sh
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"

PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"

# Set defaults
set_default_env "SLSA_LEVEL" "2"

# Parse arguments
ACTION="${1:-}"
TARGET="${2:-}"
SOURCE_URI="${3:-}"
PROVENANCE_FILE="${4:-}"

if [[ -z "${ACTION}" ]] || [[ -z "${TARGET}" ]]; then
    log_error "Usage: security-slsa-provenance <action> <target> [source_uri] [provenance_file]"
    log_error "  action:          generate, verify, inspect"
    log_error "  target:          Docker image, file path, or provenance file"
    log_error "  source_uri:      Source repository URI (for verify)"
    log_error "  provenance_file: Path to provenance file (for verify with file)"
    log_error ""
    log_error "Examples:"
    log_error "  security-slsa-provenance verify ghcr.io/user/charon:latest github.com/user/charon"
    log_error "  security-slsa-provenance verify ./dist/binary github.com/user/repo provenance.json"
    log_error "  security-slsa-provenance inspect provenance.json"
    exit 2
fi

# Validate action
case "${ACTION}" in
    generate|verify|inspect)
        ;;
    *)
        log_error "Invalid action: ${ACTION}"
        log_error "Action must be one of: generate, verify, inspect"
        exit 2
        ;;
esac

# Check required tools
log_step "ENVIRONMENT" "Validating prerequisites"

if ! command -v jq >/dev/null 2>&1; then
    log_error "jq is not installed"
    log_error "Install from: https://stedolan.github.io/jq/download/"
    exit 2
fi

if [[ "${ACTION}" == "verify" ]] && ! command -v slsa-verifier >/dev/null 2>&1; then
    log_error "slsa-verifier is not installed"
    log_error "Install from: https://github.com/slsa-framework/slsa-verifier"
    log_error "Quick install:"
    log_error "  go install github.com/slsa-framework/slsa-verifier/v2/cli/slsa-verifier@latest"
    log_error "Or:"
    log_error "  curl -sLO https://github.com/slsa-framework/slsa-verifier/releases/download/v2.6.0/slsa-verifier-linux-amd64"
    log_error "  sudo install slsa-verifier-linux-amd64 /usr/local/bin/slsa-verifier"
    exit 2
fi

if [[ "${ACTION}" == "verify" ]] && [[ "${TARGET}" =~ ^ghcr\.|^docker\.|: ]]; then
    # Docker image verification requires gh CLI
    if ! command -v gh >/dev/null 2>&1; then
        log_error "gh (GitHub CLI) is not installed (required for Docker image verification)"
        log_error "Install from: https://cli.github.com/"
        exit 2
    fi
fi

cd "${PROJECT_ROOT}"

# Execute action
case "${ACTION}" in
    generate)
        log_step "GENERATE" "Generating SLSA provenance for ${TARGET}"
        log_warning "This generates a basic provenance for testing only"
        log_warning "Production provenance must be generated by CI/CD build platform"

        if [[ ! -f "${TARGET}" ]]; then
            log_error "File not found: ${TARGET}"
            exit 1
        fi

        # Calculate digest
        DIGEST=$(sha256sum "${TARGET}" | awk '{print $1}')
        ARTIFACT_NAME=$(basename "${TARGET}")
        OUTPUT_FILE="provenance-${ARTIFACT_NAME}.json"

        # Generate basic provenance structure
        cat > "${OUTPUT_FILE}" <<EOF
{
  "_type": "https://in-toto.io/Statement/v1",
  "subject": [
    {
      "name": "${ARTIFACT_NAME}",
      "digest": {
        "sha256": "${DIGEST}"
      }
    }
  ],
  "predicateType": "https://slsa.dev/provenance/v1",
  "predicate": {
    "buildDefinition": {
      "buildType": "https://github.com/user/local-build",
      "externalParameters": {
        "source": {
          "uri": "git+https://github.com/user/charon@local",
          "digest": {
            "sha1": "0000000000000000000000000000000000000000"
          }
        }
      },
      "internalParameters": {},
      "resolvedDependencies": []
    },
    "runDetails": {
      "builder": {
        "id": "https://github.com/user/local-builder@v1.0.0"
      },
      "metadata": {
        "invocationId": "local-$(date +%s)",
        "startedOn": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
        "finishedOn": "$(date -u +%Y-%m-%dT%H:%M:%SZ)"
      }
    }
  }
}
EOF

        log_success "Generated provenance: ${OUTPUT_FILE}"
        log_warning "This provenance is NOT cryptographically signed"
        log_warning "Use only for local testing, not for production"
        ;;

    verify)
        log_step "VERIFY" "Verifying SLSA provenance for ${TARGET}"

        if [[ -z "${SOURCE_URI}" ]]; then
            log_error "Source URI is required for verification"
            log_error "Usage: security-slsa-provenance verify <target> <source_uri> [provenance_file]"
            exit 2
        fi

        # Determine if target is Docker image or file
        # Match: ghcr.io/user/repo:tag, docker.io/user/repo:tag, user/repo:tag, simple:tag, registry.io:5000/app:v1
        # Avoid: ./file, /path/to/file, file.ext, http://url
        # Strategy: Images have "name:tag" format and don't start with ./ or / and aren't files
        if [[ ! -f "${TARGET}" ]] && \
           [[ ! "${TARGET}" =~ ^\./ ]] && \
           [[ ! "${TARGET}" =~ ^/ ]] && \
           [[ ! "${TARGET}" =~ ^https?:// ]] && \
           [[ "${TARGET}" =~ : ]]; then
            # Looks like a Docker image
            log_info "Target appears to be a Docker image"

            if [[ -n "${PROVENANCE_FILE}" ]]; then
                log_warning "Provenance file parameter ignored for Docker images"
                log_warning "Provenance will be downloaded from registry"
            fi

            # Verify image with slsa-verifier
            log_info "Verifying image with slsa-verifier..."
            if slsa-verifier verify-image "${TARGET}" \
                --source-uri "github.com/${SOURCE_URI}" \
                --print-provenance 2>&1 | tee slsa-verify.log; then
                log_success "Provenance verification passed"

                # Parse SLSA level from output
                if grep -q "SLSA" slsa-verify.log; then
                    LEVEL=$(grep -oP 'SLSA Level: \K\d+' slsa-verify.log || echo "unknown")
                    log_info "SLSA Level: ${LEVEL}"

                    if [[ "${LEVEL}" =~ ^[0-9]+$ ]] && [[ "${LEVEL}" -lt "${SLSA_LEVEL}" ]]; then
                        log_warning "SLSA level ${LEVEL} is below minimum required level ${SLSA_LEVEL}"
                    fi
                fi

                rm -f slsa-verify.log
                exit 0
            else
                log_error "Provenance verification failed"
                cat slsa-verify.log >&2 || true
                rm -f slsa-verify.log
                exit 1
            fi
        else
            # File artifact
            log_info "Target appears to be a file artifact"

            if [[ ! -f "${TARGET}" ]]; then
                log_error "File not found: ${TARGET}"
                exit 1
            fi

            if [[ -z "${PROVENANCE_FILE}" ]]; then
                log_error "Provenance file is required for file verification"
                log_error "Usage: security-slsa-provenance verify <file> <source_uri> <provenance_file>"
                exit 2
            fi

            if [[ ! -f "${PROVENANCE_FILE}" ]]; then
                log_error "Provenance file not found: ${PROVENANCE_FILE}"
                exit 1
            fi

            log_info "Verifying artifact with slsa-verifier..."
            if slsa-verifier verify-artifact "${TARGET}" \
                --provenance-path "${PROVENANCE_FILE}" \
                --source-uri "github.com/${SOURCE_URI}" \
                --print-provenance 2>&1 | tee slsa-verify.log; then
                log_success "Provenance verification passed"

                # Parse SLSA level from output
                if grep -q "SLSA" slsa-verify.log; then
                    LEVEL=$(grep -oP 'SLSA Level: \K\d+' slsa-verify.log || echo "unknown")
                    log_info "SLSA Level: ${LEVEL}"

                    if [[ "${LEVEL}" =~ ^[0-9]+$ ]] && [[ "${LEVEL}" -lt "${SLSA_LEVEL}" ]]; then
                        log_warning "SLSA level ${LEVEL} is below minimum required level ${SLSA_LEVEL}"
                    fi
                fi

                rm -f slsa-verify.log
                exit 0
            else
                log_error "Provenance verification failed"
                cat slsa-verify.log >&2 || true
                rm -f slsa-verify.log
                exit 1
            fi
        fi
        ;;

    inspect)
        log_step "INSPECT" "Inspecting SLSA provenance"

        if [[ ! -f "${TARGET}" ]]; then
            log_error "Provenance file not found: ${TARGET}"
            exit 1
        fi

        # Validate JSON
        if ! jq empty "${TARGET}" 2>/dev/null; then
            log_error "Invalid JSON in provenance file"
            exit 1
        fi

        echo ""
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
        echo "                    SLSA PROVENANCE DETAILS"
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
        echo ""

        # Extract and display key fields
        PREDICATE_TYPE=$(jq -r '.predicateType // "unknown"' "${TARGET}")
        echo "Predicate Type: ${PREDICATE_TYPE}"

        # Builder
        BUILDER_ID=$(jq -r '.predicate.runDetails.builder.id // .predicate.builder.id // "unknown"' "${TARGET}")
        echo ""
        echo "Builder:"
        echo "  ID: ${BUILDER_ID}"

        # Source
        SOURCE_URI_FOUND=$(jq -r '.predicate.buildDefinition.externalParameters.source.uri // .predicate.materials[0].uri // "unknown"' "${TARGET}")
        SOURCE_DIGEST=$(jq -r '.predicate.buildDefinition.externalParameters.source.digest.sha1 // "unknown"' "${TARGET}")
        echo ""
        echo "Source Repository:"
        echo "  URI: ${SOURCE_URI_FOUND}"
        if [[ "${SOURCE_DIGEST}" != "unknown" ]]; then
            echo "  Digest: ${SOURCE_DIGEST}"
        fi

        # Subject
        SUBJECT_NAME=$(jq -r '.subject[0].name // "unknown"' "${TARGET}")
        SUBJECT_DIGEST=$(jq -r '.subject[0].digest.sha256 // "unknown"' "${TARGET}")
        echo ""
        echo "Subject:"
        echo "  Name: ${SUBJECT_NAME}"
        echo "  Digest: sha256:${SUBJECT_DIGEST:0:12}..."

        # Build metadata
        STARTED=$(jq -r '.predicate.runDetails.metadata.startedOn // .predicate.metadata.buildStartedOn // "unknown"' "${TARGET}")
        FINISHED=$(jq -r '.predicate.runDetails.metadata.finishedOn // .predicate.metadata.buildFinishedOn // "unknown"' "${TARGET}")
        echo ""
        echo "Build Metadata:"
        if [[ "${STARTED}" != "unknown" ]]; then
            echo "  Started: ${STARTED}"
        fi
        if [[ "${FINISHED}" != "unknown" ]]; then
            echo "  Finished: ${FINISHED}"
        fi

        # Materials/Dependencies
        MATERIALS_COUNT=$(jq '.predicate.buildDefinition.resolvedDependencies // .predicate.materials // [] | length' "${TARGET}")
        if [[ "${MATERIALS_COUNT}" -gt 0 ]]; then
            echo ""
            echo "Materials (Dependencies): ${MATERIALS_COUNT}"
            jq -r '.predicate.buildDefinition.resolvedDependencies // .predicate.materials // [] | .[] | "  - \(.uri // .name // "unknown")"' "${TARGET}" | head -n 5
            if [[ "${MATERIALS_COUNT}" -gt 5 ]]; then
                echo "  ... and $((MATERIALS_COUNT - 5)) more"
            fi
        fi

        echo ""
        echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
        echo ""

        log_success "Provenance inspection complete"
        ;;
esac

exit 0
