#!/usr/bin/env bash
# incusos-seed - Generate IncusOS seed archives for installation customization
#
# Creates tar archives or FAT images containing seed configuration files
# for IncusOS installations. Supports all seed file types including install,
# applications, Incus preseed, Operations Center, network, and update config.
#
# Usage: incusos-seed [OPTIONS]
# Run 'incusos-seed --help' for full usage information.

set -euo pipefail

readonly VERSION="0.1.0"
readonly SCRIPT_NAME="incusos-seed"

# ---------------------------------------------------------------------------
# Color and formatting
# ---------------------------------------------------------------------------

setup_colors() {
    if [[ -t 1 ]] && [[ "${NO_COLOR:-}" != "1" ]] && [[ "${TERM:-}" != "dumb" ]]; then
        RED='\033[0;31m'
        GREEN='\033[0;32m'
        YELLOW='\033[0;33m'
        BLUE='\033[0;34m'
        CYAN='\033[0;36m'
        BOLD='\033[1m'
        DIM='\033[2m'
        RESET='\033[0m'
    else
        RED='' GREEN='' YELLOW='' BLUE='' CYAN='' BOLD='' DIM='' RESET=''
    fi
}

info()    { echo -e "${BLUE}[info]${RESET}    $*"; }
success() { echo -e "${GREEN}[ok]${RESET}      $*"; }
warn()    { echo -e "${YELLOW}[warn]${RESET}    $*" >&2; }
error()   { echo -e "${RED}[error]${RESET}   $*" >&2; }
step()    { echo -e "${CYAN}[step]${RESET}    ${BOLD}$*${RESET}"; }
detail()  { echo -e "${DIM}          $*${RESET}"; }

# ---------------------------------------------------------------------------
# Help
# ---------------------------------------------------------------------------

usage() {
    cat <<EOF
${BOLD}${SCRIPT_NAME}${RESET} v${VERSION} - Generate IncusOS seed archives

${BOLD}USAGE${RESET}
    ${SCRIPT_NAME} [OPTIONS]

${BOLD}OPTIONS${RESET}
    ${BOLD}-A, --app${RESET} APP            Application to configure: ${CYAN}incus${RESET}, ${CYAN}operations-center${RESET}
                             (default: incus)
    ${BOLD}-d, --defaults${RESET}           Apply default configuration (ZFS pool, bridge, port 8443)
    ${BOLD}-c, --cert${RESET} FILE          Path to client certificate PEM file
                             (default: auto-detect from local Incus installation)
        ${BOLD}--no-cert${RESET}            Do not inject any client certificate
    ${BOLD}-o, --output${RESET} FILE        Output file path (default: incusos-seed.tar)

  ${BOLD}Install options:${RESET}
        ${BOLD}--disk-target${RESET} ID     Target disk ID pattern for /dev/disk/by-id/ (e.g. "virtio-*")
        ${BOLD}--force-install${RESET}      Overwrite existing installation without prompting
        ${BOLD}--force-reboot${RESET}       Automatically reboot after installation
        ${BOLD}--missing-tpm${RESET}        Allow installation without TPM 2.0
        ${BOLD}--missing-secureboot${RESET} Allow installation without Secure Boot

  ${BOLD}Network options:${RESET}
        ${BOLD}--hostname${RESET} NAME      Set system hostname
        ${BOLD}--domain${RESET} NAME        Set system domain
        ${BOLD}--dns${RESET} SERVERS        Comma-separated DNS servers (e.g. "8.8.8.8,1.1.1.1")
        ${BOLD}--ip${RESET} ADDR/PREFIX    Static IP in CIDR notation (e.g. "192.168.102.100/22")
        ${BOLD}--gateway${RESET} ADDR       Default gateway (required with --ip)
        ${BOLD}--iface${RESET} NAME        Network interface name (default: ens18 for Proxmox VMs)

  ${BOLD}Update options:${RESET}
        ${BOLD}--channel${RESET} CHANNEL    Update channel: ${CYAN}stable${RESET}, ${CYAN}testing${RESET} (default: stable)
        ${BOLD}--auto-reboot${RESET}        Enable automatic reboot for updates

  ${BOLD}Output options:${RESET}
    ${BOLD}-f, --format${RESET} FORMAT      Output format: ${CYAN}tar${RESET}, ${CYAN}iso${RESET}, ${CYAN}fat${RESET} (default: tar)
                             tar: for use with flasher-tool --seed
                             iso: ISO 9660 image with SEED_DATA label for CD-ROM
                             fat: FAT image with SEED_DATA label for external media
        ${BOLD}--fat-size${RESET} SIZE      FAT image size in MiB (default: 10)

  ${BOLD}General:${RESET}
        ${BOLD}--dry-run${RESET}            Show generated seed files without creating output
    ${BOLD}-q, --quiet${RESET}              Suppress informational output
    ${BOLD}-h, --help${RESET}               Show this help message
    ${BOLD}-V, --version${RESET}            Show version

${BOLD}EXAMPLES${RESET}
    # Standalone Incus with defaults and auto-detected certificate
    ${SCRIPT_NAME} --defaults

    # Operations Center with explicit certificate
    ${SCRIPT_NAME} --app operations-center --defaults --cert ~/.config/incus/client.crt

    # Cluster node (no defaults) with forced install on virtio disk
    ${SCRIPT_NAME} --disk-target 'virtio-*' --force-install --force-reboot

    # Create an ISO 9660 image for CD-ROM seed delivery (e.g. Proxmox VMs)
    ${SCRIPT_NAME} --format iso --defaults --output seed.iso

    # Create a FAT image for SEED_DATA partition
    ${SCRIPT_NAME} --format fat --defaults --output seed.img

    # Preview what would be generated
    ${SCRIPT_NAME} --defaults --dry-run

${BOLD}SEED FILES REFERENCE${RESET}
    The following files are generated inside the archive:

    ${CYAN}install.yaml${RESET}              Installation target, security, and reboot settings
    ${CYAN}applications.yaml${RESET}         Application selection (incus, operations-center)
    ${CYAN}incus.yaml${RESET}                Incus preseed (defaults, certificates)
    ${CYAN}operations-center.yaml${RESET}    Operations Center config (when --app=operations-center)
    ${CYAN}network.yaml${RESET}              Network configuration (hostname, DNS, static IP)
    ${CYAN}update.yaml${RESET}               Update channel and reboot policy

EOF
    exit 0
}

# ---------------------------------------------------------------------------
# Argument parsing
# ---------------------------------------------------------------------------

# Defaults
APP="incus"
APPLY_DEFAULTS=false
CERT_FILE=""
NO_CERT=false
OUTPUT=""
DISK_TARGET=""
FORCE_INSTALL=false
FORCE_REBOOT=false
MISSING_TPM=false
MISSING_SECUREBOOT=false
HOSTNAME_OPT=""
DOMAIN_OPT=""
DNS_SERVERS=""
STATIC_IP=""
GATEWAY=""
IFACE="ens18"
CHANNEL="stable"
AUTO_REBOOT=false
FORMAT="tar"
FAT_SIZE=10
DRY_RUN=false
QUIET=false

parse_args() {
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -A|--app)
                APP="${2:?'--app requires a value'}"
                shift 2
                ;;
            -d|--defaults)
                APPLY_DEFAULTS=true
                shift
                ;;
            -c|--cert)
                CERT_FILE="${2:?'--cert requires a file path'}"
                shift 2
                ;;
            --no-cert)
                NO_CERT=true
                shift
                ;;
            -o|--output)
                OUTPUT="${2:?'--output requires a file path'}"
                shift 2
                ;;
            --disk-target)
                DISK_TARGET="${2:?'--disk-target requires a value'}"
                shift 2
                ;;
            --force-install)
                FORCE_INSTALL=true
                shift
                ;;
            --force-reboot)
                FORCE_REBOOT=true
                shift
                ;;
            --missing-tpm)
                MISSING_TPM=true
                shift
                ;;
            --missing-secureboot)
                MISSING_SECUREBOOT=true
                shift
                ;;
            --hostname)
                HOSTNAME_OPT="${2:?'--hostname requires a value'}"
                shift 2
                ;;
            --domain)
                DOMAIN_OPT="${2:?'--domain requires a value'}"
                shift 2
                ;;
            --dns)
                DNS_SERVERS="${2:?'--dns requires a value'}"
                shift 2
                ;;
            --ip)
                STATIC_IP="${2:?'--ip requires ADDR/PREFIX (e.g. 192.168.102.100/22)'}"
                shift 2
                ;;
            --gateway)
                GATEWAY="${2:?'--gateway requires an address'}"
                shift 2
                ;;
            --iface)
                IFACE="${2:?'--iface requires a name'}"
                shift 2
                ;;
            --channel)
                CHANNEL="${2:?'--channel requires a value'}"
                shift 2
                ;;
            --auto-reboot)
                AUTO_REBOOT=true
                shift
                ;;
            -f|--format)
                FORMAT="${2:?'--format requires a value'}"
                shift 2
                ;;
            --fat-size)
                FAT_SIZE="${2:?'--fat-size requires a value'}"
                shift 2
                ;;
            --dry-run)
                DRY_RUN=true
                shift
                ;;
            -q|--quiet)
                QUIET=true
                shift
                ;;
            -h|--help)
                usage
                ;;
            -V|--version)
                echo "${SCRIPT_NAME} v${VERSION}"
                exit 0
                ;;
            -*)
                error "Unknown option: $1"
                echo "Run '${SCRIPT_NAME} --help' for usage information." >&2
                exit 1
                ;;
            *)
                error "Unexpected argument: $1"
                echo "Run '${SCRIPT_NAME} --help' for usage information." >&2
                exit 1
                ;;
        esac
    done
}

# ---------------------------------------------------------------------------
# Platform detection
# ---------------------------------------------------------------------------

# ISO_TOOL is set by find_iso_tool() and used by create_iso_output()
ISO_TOOL=""

find_iso_tool() {
    # Prefer genisoimage (Linux), fall back to mkisofs (macOS cdrtools)
    if command -v genisoimage &>/dev/null; then
        ISO_TOOL="genisoimage"
        return 0
    elif command -v mkisofs &>/dev/null; then
        ISO_TOOL="mkisofs"
        return 0
    fi
    return 1
}

# MKFS_FAT_TOOL is set by find_mkfs_fat_tool()
MKFS_FAT_TOOL=""

find_mkfs_fat_tool() {
    if command -v mkfs.fat &>/dev/null; then
        MKFS_FAT_TOOL="mkfs.fat"
        return 0
    elif [[ -x /usr/sbin/mkfs.fat ]]; then
        MKFS_FAT_TOOL="/usr/sbin/mkfs.fat"
        return 0
    elif [[ -x /sbin/mkfs.fat ]]; then
        MKFS_FAT_TOOL="/sbin/mkfs.fat"
        return 0
    elif command -v newfs_msdos &>/dev/null; then
        MKFS_FAT_TOOL="newfs_msdos"
        return 0
    fi
    return 1
}

# ---------------------------------------------------------------------------
# Validation
# ---------------------------------------------------------------------------

validate_args() {
    case "$APP" in
        incus|operations-center) ;;
        *)
            error "Invalid application: ${APP}"
            error "Supported: incus, operations-center"
            exit 1
            ;;
    esac

    case "$FORMAT" in
        tar|iso|fat) ;;
        *)
            error "Invalid output format: ${FORMAT}"
            error "Supported: tar, iso, fat"
            exit 1
            ;;
    esac

    case "$CHANNEL" in
        stable|testing) ;;
        *)
            error "Invalid channel: ${CHANNEL}"
            error "Supported: stable, testing"
            exit 1
            ;;
    esac

    if [[ -n "$CERT_FILE" ]] && [[ "$NO_CERT" == true ]]; then
        error "Cannot use both --cert and --no-cert"
        exit 1
    fi

    if [[ -n "$STATIC_IP" ]] && [[ -z "$GATEWAY" ]]; then
        error "--ip requires --gateway"
        exit 1
    fi

    if [[ -n "$STATIC_IP" ]] && [[ "$STATIC_IP" != */* ]]; then
        error "--ip must include prefix length (e.g. 192.168.102.100/22)"
        exit 1
    fi

    if [[ -n "$CERT_FILE" ]] && [[ ! -f "$CERT_FILE" ]]; then
        error "Certificate file not found: ${CERT_FILE}"
        exit 1
    fi

    if [[ "$FORMAT" == "iso" ]]; then
        if ! find_iso_tool; then
            error "ISO 9660 image creation requires genisoimage (Linux) or mkisofs (macOS)"
            case "$(uname -s)" in
                Darwin) error "Install with: brew install cdrtools" ;;
                *)      error "Install with: sudo apt install genisoimage" ;;
            esac
            exit 1
        fi
    fi

    if [[ "$FORMAT" == "fat" ]]; then
        local has_mkfs=false
        if find_mkfs_fat_tool; then
            has_mkfs=true
        fi
        if ! command -v mcopy &>/dev/null && [[ "$has_mkfs" != true ]]; then
            error "FAT image creation requires mtools (mcopy) or dosfstools (mkfs.fat)"
            case "$(uname -s)" in
                Darwin) error "Install with: brew install mtools" ;;
                *)      error "Install with: sudo apt install mtools dosfstools" ;;
            esac
            exit 1
        fi
    fi

    # Set default output filename
    if [[ -z "$OUTPUT" ]]; then
        case "$FORMAT" in
            tar) OUTPUT="incusos-seed.tar" ;;
            iso) OUTPUT="incusos-seed.iso" ;;
            fat) OUTPUT="incusos-seed.img" ;;
        esac
    fi
}

# ---------------------------------------------------------------------------
# Certificate detection
# ---------------------------------------------------------------------------

CERT_CONTENT=""

detect_client_cert() {
    if [[ "$NO_CERT" == true ]]; then
        [[ "$QUIET" != true ]] && info "Skipping certificate injection (--no-cert)"
        return
    fi

    if [[ -n "$CERT_FILE" ]]; then
        step "Loading client certificate from ${CERT_FILE}"
        CERT_CONTENT=$(<"$CERT_FILE")
        if [[ "$CERT_CONTENT" != *"BEGIN CERTIFICATE"* ]]; then
            error "File does not appear to be a PEM certificate: ${CERT_FILE}"
            exit 1
        fi
        success "Certificate loaded"
        return
    fi

    # Auto-detection: prefer reading cert files directly (works with all
    # Incus versions including 6.0 LTS which lacks 'get-client-certificate').
    step "Auto-detecting client certificate"

    # 1) Check common on-disk certificate locations first
    local cert_paths=(
        "${HOME}/.config/incus/client.crt"
        "${HOME}/snap/incus/common/config/client.crt"
        "${HOME}/.config/lxc/client.crt"
    )

    for path in "${cert_paths[@]}"; do
        if [[ -f "$path" ]]; then
            CERT_CONTENT=$(<"$path")
            if [[ "$CERT_CONTENT" == *"BEGIN CERTIFICATE"* ]]; then
                success "Certificate loaded from ${path}"
                return
            fi
            detail "File exists but does not contain a valid PEM certificate: ${path}"
        fi
    done

    # 2) Try the incus CLI (only works with Incus >= 6.3)
    if command -v incus &>/dev/null; then
        local cert
        if cert=$(incus remote get-client-certificate 2>/dev/null); then
            CERT_CONTENT="$cert"
            success "Certificate obtained via Incus CLI"
            return
        fi
        local incus_version
        incus_version=$(incus version 2>/dev/null | sed -n 's/.*Client version: \([0-9.]*\).*/\1/p' || echo "unknown")
        [[ -z "$incus_version" ]] && incus_version="unknown"
        detail "Incus CLI v${incus_version} found but no certificate available"
        detail "Generate one with: incus remote list  (triggers auto-generation)"
    fi

    # 3) Nothing found -- report based on context
    if [[ "$APP" == "operations-center" ]]; then
        error "No client certificate found"
        error "Operations Center requires at least one trusted certificate for access"
        echo "" >&2
        error "Options:"
        error "  --cert FILE     Provide a certificate file directly"
        error "  Generate one:   incus remote list  (creates ~/.config/incus/client.crt)"
        error "  --no-cert       Skip certificate injection (you will be locked out!)"
        exit 1
    fi

    warn "No client certificate found"
    if command -v incus &>/dev/null; then
        warn "Run 'incus remote list' to generate a client certificate, then re-run this script"
    else
        warn "The Incus client is not installed on this machine"
        warn "Install it to enable auto-detection (see: https://github.com/lxc/incus)"
    fi
    warn "Use --cert FILE to provide a certificate, or --no-cert to suppress this warning"
}

# ---------------------------------------------------------------------------
# Seed file generation
# ---------------------------------------------------------------------------

WORKDIR=""

setup_workdir() {
    WORKDIR=$(mktemp -d "${TMPDIR:-/tmp}/${SCRIPT_NAME}-XXXXXX")
    trap 'rm -rf "$WORKDIR"' EXIT
}

generate_install_yaml() {
    local file="${WORKDIR}/install.yaml"

    step "Generating install.yaml"

    {
        echo "# IncusOS installation configuration"
        echo "# Generated by ${SCRIPT_NAME} v${VERSION} on $(date '+%Y-%m-%dT%H:%M:%S%z')"

        if [[ "$FORCE_INSTALL" == true ]]; then
            echo "force_install: true"
        fi

        if [[ "$FORCE_REBOOT" == true ]]; then
            echo "force_reboot: true"
        fi

        if [[ -n "$DISK_TARGET" ]]; then
            echo "target:"
            echo "  id: \"${DISK_TARGET}\""
        fi

        if [[ "$MISSING_TPM" == true ]] || [[ "$MISSING_SECUREBOOT" == true ]]; then
            echo "security:"
            if [[ "$MISSING_TPM" == true ]]; then
                echo "  missing_tpm: true"
            fi
            if [[ "$MISSING_SECUREBOOT" == true ]]; then
                echo "  missing_secure_boot: true"
            fi
        fi
    } > "$file"

    if [[ "$DRY_RUN" == true ]]; then
        detail "--- install.yaml ---"
        while IFS= read -r line; do detail "$line"; done < "$file"
    else
        success "install.yaml"
    fi
}

generate_applications_yaml() {
    local file="${WORKDIR}/applications.yaml"

    step "Generating applications.yaml"

    {
        echo "# IncusOS application selection"
        echo "applications:"
        echo "  - name: ${APP}"
    } > "$file"

    if [[ "$DRY_RUN" == true ]]; then
        detail "--- applications.yaml ---"
        while IFS= read -r line; do detail "$line"; done < "$file"
    else
        success "applications.yaml (${APP})"
    fi
}

generate_incus_yaml() {
    local file="${WORKDIR}/incus.yaml"

    step "Generating incus.yaml"

    {
        echo "# Incus preseed configuration"
        echo "apply_defaults: ${APPLY_DEFAULTS}"

        if [[ -n "$CERT_CONTENT" ]]; then
            echo "preseed:"
            echo "  certificates:"
            echo "    - name: \"auto-injected-client\""
            echo "      type: \"client\""
            echo "      certificate: |-"
            # Indent each line of the certificate
            while IFS= read -r line; do
                echo "        ${line}"
            done <<< "$CERT_CONTENT"
        fi
    } > "$file"

    if [[ "$DRY_RUN" == true ]]; then
        detail "--- incus.yaml ---"
        while IFS= read -r line; do detail "$line"; done < "$file"
    else
        local desc="defaults=$(bool_str $APPLY_DEFAULTS)"
        [[ -n "$CERT_CONTENT" ]] && desc+=", certificate=injected"
        success "incus.yaml (${desc})"
    fi
}

generate_ops_center_yaml() {
    local file="${WORKDIR}/operations-center.yaml"

    step "Generating operations-center.yaml"

    {
        echo "# Operations Center configuration"
        echo "apply_defaults: ${APPLY_DEFAULTS}"

        if [[ -n "$CERT_CONTENT" ]]; then
            echo "trusted_client_certificates:"
            echo "  - |"
            while IFS= read -r line; do
                echo "    ${line}"
            done <<< "$CERT_CONTENT"
        fi
    } > "$file"

    if [[ "$DRY_RUN" == true ]]; then
        detail "--- operations-center.yaml ---"
        while IFS= read -r line; do detail "$line"; done < "$file"
    else
        local desc="defaults=$(bool_str $APPLY_DEFAULTS)"
        [[ -n "$CERT_CONTENT" ]] && desc+=", certificate=injected"
        success "operations-center.yaml (${desc})"
    fi
}

generate_network_yaml() {
    # Only generate if network options were specified
    if [[ -z "$HOSTNAME_OPT" ]] && [[ -z "$DOMAIN_OPT" ]] && [[ -z "$DNS_SERVERS" ]] && [[ -z "$STATIC_IP" ]]; then
        return
    fi

    local file="${WORKDIR}/network.yaml"

    step "Generating network.yaml"

    {
        echo "# Network configuration"

        if [[ -n "$HOSTNAME_OPT" ]] || [[ -n "$DOMAIN_OPT" ]] || [[ -n "$DNS_SERVERS" ]]; then
            echo "dns:"
            [[ -n "$HOSTNAME_OPT" ]] && echo "  hostname: \"${HOSTNAME_OPT}\""
            [[ -n "$DOMAIN_OPT" ]]   && echo "  domain: \"${DOMAIN_OPT}\""

            if [[ -n "$DNS_SERVERS" ]]; then
                echo "  nameservers:"
                IFS=',' read -ra servers <<< "$DNS_SERVERS"
                for srv in "${servers[@]}"; do
                    echo "    - \"$(echo "$srv" | xargs)\""
                done
            fi
        fi

        # Static IP configuration
        if [[ -n "$STATIC_IP" ]]; then
            echo ""
            echo "interfaces:"
            echo "  - name: \"mgmt\""
            echo "    hwaddr: \"${IFACE}\""
            echo "    addresses:"
            echo "      - \"${STATIC_IP}\""
            echo "    roles:"
            echo "      - management"
            echo "    routes:"
            echo "      - to: \"0.0.0.0/0\""
            echo "        via: \"${GATEWAY}\""
        fi
    } > "$file"

    if [[ "$DRY_RUN" == true ]]; then
        detail "--- network.yaml ---"
        while IFS= read -r line; do detail "$line"; done < "$file"
    else
        local desc=""
        [[ -n "$HOSTNAME_OPT" ]] && desc+="hostname=${HOSTNAME_OPT}"
        [[ -n "$STATIC_IP" ]]   && desc+=", ip=${STATIC_IP}"
        [[ -n "$DNS_SERVERS" ]]  && desc+=", dns=${DNS_SERVERS}"
        success "network.yaml (${desc})"
    fi
}

generate_update_yaml() {
    local file="${WORKDIR}/update.yaml"

    step "Generating update.yaml"

    {
        echo "# Update configuration"
        echo "# Always generated to ensure explicit check_frequency on first boot"
        echo "channel: \"${CHANNEL}\""
        echo "auto_reboot: ${AUTO_REBOOT}"
        echo "check_frequency: \"6h\""
    } > "$file"

    if [[ "$DRY_RUN" == true ]]; then
        detail "--- update.yaml ---"
        while IFS= read -r line; do detail "$line"; done < "$file"
    else
        success "update.yaml (channel=${CHANNEL}, auto_reboot=$(bool_str $AUTO_REBOOT))"
    fi
}

# ---------------------------------------------------------------------------
# Output creation
# ---------------------------------------------------------------------------

create_tar_output() {
    step "Creating tar archive: ${OUTPUT}"

    tar -cf "$OUTPUT" -C "$WORKDIR" .

    local size
    size=$(du -h "$OUTPUT" | cut -f1)
    success "Seed archive created: ${OUTPUT} (${size})"
}

create_iso_output() {
    step "Creating ISO 9660 image: ${OUTPUT}"

    # ISO_TOOL was set by find_iso_tool() during validation
    # Both genisoimage and mkisofs accept the same core flags
    "$ISO_TOOL" -o "$OUTPUT" -V SEED_DATA -J -r "$WORKDIR"/ 2>/dev/null

    local size
    size=$(du -h "$OUTPUT" | cut -f1)
    success "ISO 9660 seed image created: ${OUTPUT} (${size})"
}

create_fat_output() {
    step "Creating FAT image: ${OUTPUT} (${FAT_SIZE} MiB)"

    # Create empty image
    dd if=/dev/zero of="$OUTPUT" bs=1048576 count="$FAT_SIZE" 2>/dev/null

    # MKFS_FAT_TOOL was set by find_mkfs_fat_tool() during validation
    if [[ -n "$MKFS_FAT_TOOL" ]]; then
        if [[ "$MKFS_FAT_TOOL" == "newfs_msdos" ]]; then
            # macOS built-in: -F 12 for FAT12, -v for volume label
            newfs_msdos -F 12 -v SEED_DATA "$OUTPUT" >/dev/null
        else
            # Linux mkfs.fat
            "$MKFS_FAT_TOOL" -n SEED_DATA "$OUTPUT" >/dev/null
        fi

        if command -v mcopy &>/dev/null; then
            for f in "${WORKDIR}"/*.yaml; do
                [[ -f "$f" ]] && mcopy -i "$OUTPUT" "$f" "::/$(basename "$f")"
            done
        else
            warn "mtools not installed -- FAT image created but files not copied"
            warn "Install mtools and re-run, or manually mount and copy seed files"
            warn "Files are in: ${WORKDIR}/"
            trap - EXIT
            return
        fi
    elif command -v mcopy &>/dev/null; then
        # mtools can format too
        mformat -i "$OUTPUT" -v SEED_DATA ::
        for f in "${WORKDIR}"/*.yaml; do
            [[ -f "$f" ]] && mcopy -i "$OUTPUT" "$f" "::/$(basename "$f")"
        done
    fi

    local size
    size=$(du -h "$OUTPUT" | cut -f1)
    success "FAT seed image created: ${OUTPUT} (${size})"
}

# ---------------------------------------------------------------------------
# Utilities
# ---------------------------------------------------------------------------

bool_str() {
    if [[ "$1" == true ]]; then echo "yes"; else echo "no"; fi
}

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------

print_summary() {
    echo ""
    echo -e "${BOLD}Seed archive summary${RESET}"
    echo -e "  Application:   ${CYAN}${APP}${RESET}"
    echo -e "  Defaults:      $(if [[ "$APPLY_DEFAULTS" == true ]]; then echo "${GREEN}yes${RESET}"; else echo "${YELLOW}no${RESET}"; fi)"
    echo -e "  Certificate:   $(if [[ -n "$CERT_CONTENT" ]]; then echo "${GREEN}injected${RESET}"; else echo "${DIM}none${RESET}"; fi)"
    echo -e "  Format:        ${FORMAT}"
    echo -e "  Output:        ${BOLD}${OUTPUT}${RESET}"

    if [[ -n "$DISK_TARGET" ]]; then
        echo -e "  Disk target:   ${DISK_TARGET}"
    fi
    if [[ "$MISSING_TPM" == true ]]; then
        echo -e "  Security:      ${YELLOW}TPM not required${RESET}"
    fi
    if [[ "$MISSING_SECUREBOOT" == true ]]; then
        echo -e "  Security:      ${YELLOW}Secure Boot not required${RESET}"
    fi

    echo ""

    if [[ "$FORMAT" == "tar" ]]; then
        echo -e "${DIM}  Use with flasher-tool:${RESET}"
        echo -e "    flasher-tool --seed ${OUTPUT}"
    elif [[ "$FORMAT" == "iso" ]]; then
        echo -e "${DIM}  Attach as CD-ROM to the VM.${RESET}"
        echo -e "${DIM}  IncusOS will detect the SEED_DATA volume label at boot.${RESET}"
    elif [[ "$FORMAT" == "fat" ]]; then
        echo -e "${DIM}  Attach as secondary disk/ISO to the VM.${RESET}"
        echo -e "${DIM}  IncusOS will detect the SEED_DATA label at boot.${RESET}"
    fi
    echo ""
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

main() {
    setup_colors
    parse_args "$@"
    validate_args

    if [[ "$QUIET" != true ]] && [[ "$DRY_RUN" != true ]]; then
        echo -e "${BOLD}${SCRIPT_NAME}${RESET} v${VERSION}"
        echo ""
    fi

    if [[ "$DRY_RUN" == true ]]; then
        echo -e "${BOLD}Dry run -- showing generated seed files${RESET}"
        echo ""
    fi

    setup_workdir
    detect_client_cert

    echo ""

    # Generate all seed files
    generate_install_yaml
    generate_applications_yaml

    case "$APP" in
        incus)
            generate_incus_yaml
            ;;
        operations-center)
            generate_ops_center_yaml
            ;;
    esac

    generate_network_yaml
    generate_update_yaml

    echo ""

    # Create output
    if [[ "$DRY_RUN" == true ]]; then
        info "Dry run complete -- no files were created"
    else
        case "$FORMAT" in
            tar) create_tar_output ;;
            iso) create_iso_output ;;
            fat) create_fat_output ;;
        esac

        if [[ "$QUIET" != true ]]; then
            print_summary
        fi
    fi
}

main "$@"
