# Audit logging CLI commands for Provisioning platform
#
# Provides query, export, and management of audit logs

use std assert

# Query audit logs with filters
#
# @param --user: Filter by user ID
# @param --action: Filter by action type
# @param --resource: Filter by resource name
# @param --workspace: Filter by workspace name
# @param --status: Filter by status (success, failure, error)
# @param --from: Filter by start date (RFC3339 or relative like "1d", "1w", "1M")
# @param --to: Filter by end date (RFC3339 or relative)
# @param --ip: Filter by IP address
# @param --limit: Maximum number of results (default: 100)
# @param --offset: Offset for pagination (default: 0)
# @param --sort-by: Sort field (timestamp, user, action)
# @param --sort-desc: Sort in descending order
# @param --out: Output format (json, table, csv)
#
# @example Query all server creates by a user
#   audit query --user "user123" --action "server_create"
#
# @example Query failed operations in last 24 hours
#   audit query --status "failure" --from "1d" --out table
export def "audit query" [
    --user: string                # Filter by user ID
    --action: string              # Filter by action type
    --resource: string            # Filter by resource
    --workspace: string           # Filter by workspace
    --status: string              # Filter by status
    --from: string                # Start date (RFC3339 or relative)
    --to: string                  # End date (RFC3339 or relative)
    --ip: string                  # Filter by IP address
    --limit: int = 100            # Maximum results
    --offset: int = 0             # Pagination offset
    --sort-by: string = "timestamp"  # Sort field
    --sort-desc                   # Sort descending
    --out: string = "table"       # Output format
] {
    # Convert relative dates to absolute
    let from_date = if ($from | is-not-empty) {
        parse_relative_date $from
    } else { null }

    let to_date = if ($to | is-not-empty) {
        parse_relative_date $to
    } else { null }

    # Build query parameters
    let query = {
        filter: {
            user_id: $user
            action_type: $action
            resource: $resource
            workspace: $workspace
            status: $status
            from: $from_date
            to: $to_date
            ip: $ip
        }
        limit: $limit
        offset: $offset
        sort_by: $sort_by
        sort_desc: $sort_desc
    }

    # Call orchestrator API
    let orchestrator_url = get_orchestrator_url
    let response = http post $"($orchestrator_url)/api/v1/audit/query" $query

    if ($response | get success) {
        let events = ($response | get data)

        # Format output
        match $out {
            "json" => { $events | to json }
            "csv" => { $events | to csv }
            "table" => {
                $events | select event_id timestamp user.id action.action_type action.resource result.status result.duration_ms
                    | rename event_id timestamp user action resource status duration_ms
                    | table
            }
            _ => { $events }
        }
    } else {
        error make {
            msg: "Failed to query audit logs"
            label: {
                text: ($response | get error)
                span: (metadata $response).span
            }
        }
    }
}

# Export audit logs to file
#
# @param format: Export format (json, jsonlines, csv, splunk, elastic)
# @param --output: Output file path
# @param --user: Filter by user ID
# @param --action: Filter by action type
# @param --from: Start date filter
# @param --to: End date filter
#
# @example Export last 7 days to JSON
#   audit export json --output audit-export.json --from "7d"
#
# @example Export to Splunk format
#   audit export splunk --output splunk-events.json
export def "audit export" [
    format: string                # Export format (json, jsonlines, csv, splunk, elastic)
    --output: string              # Output file path
    --user: string                # Filter by user ID
    --action: string              # Filter by action type
    --resource: string            # Filter by resource
    --workspace: string           # Filter by workspace
    --status: string              # Filter by status
    --from: string                # Start date filter
    --to: string                  # End date filter
] {
    # Validate format
    let valid_formats = ["json" "jsonlines" "csv" "splunk" "elastic"]
    if ($format not-in $valid_formats) {
        error make {
            msg: $"Invalid format: ($format)"
            label: {
                text: $"Valid formats: ($valid_formats | str join ', ')"
                span: (metadata $format).span
            }
        }
    }

    # Convert relative dates
    let from_date = if ($from | is-not-empty) {
        parse_relative_date $from
    } else { null }

    let to_date = if ($to | is-not-empty) {
        parse_relative_date $to
    } else { null }

    # Build export request
    let request = {
        format: $format
        filter: {
            user_id: $user
            action_type: $action
            resource: $resource
            workspace: $workspace
            status: $status
            from: $from_date
            to: $to_date
        }
    }

    # Call orchestrator API
    let orchestrator_url = get_orchestrator_url
    let response = http post $"($orchestrator_url)/api/v1/audit/export" $request

    if ($response | get success) {
        let data = ($response | get data)

        # Write to file if output specified
        if ($output | is-not-empty) {
            $data | save --force $output
            print $"✓ Audit logs exported to: ($output)"
        } else {
            # Print to stdout
            $data
        }
    } else {
        error make {
            msg: "Failed to export audit logs"
            label: {
                text: ($response | get error)
                span: (metadata $response).span
            }
        }
    }
}

# Show audit log statistics
#
# @example Display audit statistics
#   audit stats
export def "audit stats" [] {
    let orchestrator_url = get_orchestrator_url
    let response = http get $"($orchestrator_url)/api/v1/audit/stats"

    if ($response | get success) {
        let stats = ($response | get data)

        print "\nAudit Log Statistics:\n"

        [
            ["Metric" "Value"];
            ["Total Events" ($stats.total_events | into string)]
            ["Success Events" ($stats.success_events | into string)]
            ["Failure Events" ($stats.failure_events | into string)]
            ["Error Events" ($stats.error_events | into string)]
            ["Buffered Events" ($stats.buffered_events | into string)]
            ["Flushed Events" ($stats.flushed_events | into string)]
        ] | table
    } else {
        error make {
            msg: "Failed to get audit statistics"
            label: {
                text: ($response | get error)
                span: (metadata $response).span
            }
        }
    }
}

# Show storage statistics
#
# @example Display storage statistics
#   audit storage-stats
export def "audit storage-stats" [] {
    let orchestrator_url = get_orchestrator_url
    let response = http get $"($orchestrator_url)/api/v1/audit/storage-stats"

    if ($response | get success) {
        let stats = ($response | get data)

        print "\nAudit Storage Statistics:\n"

        [
            ["Metric" "Value"];
            ["Total Events" ($stats.total_events | into string)]
            ["Total Size" (format_bytes $stats.total_size_bytes)]
            ["Oldest Event" ($stats.oldest_event | default "N/A")]
            ["Newest Event" ($stats.newest_event | default "N/A")]
        ] | table
    } else {
        error make {
            msg: "Failed to get storage statistics"
            label: {
                text: ($response | get error)
                span: (metadata $response).span
            }
        }
    }
}

# Apply retention policy to audit logs
#
# @param --max-age-days: Maximum age in days (default: 365)
# @param --archive: Archive before deletion
# @param --archive-path: Archive destination path
# @param --yes: Skip confirmation
#
# @example Apply 90-day retention policy
#   audit apply-retention --max-age-days 90 --archive --yes
export def "audit apply-retention" [
    --max-age-days: int = 365     # Maximum age in days
    --archive                     # Archive before deletion
    --archive-path: string        # Archive destination
    --yes                         # Skip confirmation
] {
    if not $yes {
        print $"⚠️  This will delete audit logs older than ($max-age_days) days"
        let confirm = (input "Continue? (yes/no): ")
        if ($confirm != "yes") {
            print "Cancelled"
            return
        }
    }

    let policy = {
        max_age_days: $max_age_days
        auto_apply: false
        archive_before_delete: $archive
        archive_path: $archive_path
    }

    let orchestrator_url = get_orchestrator_url
    let response = http post $"($orchestrator_url)/api/v1/audit/apply-retention" $policy

    if ($response | get success) {
        let deleted = ($response | get data)
        print $"✓ Retention policy applied: ($deleted) events processed"
    } else {
        error make {
            msg: "Failed to apply retention policy"
            label: {
                text: ($response | get error)
                span: (metadata $response).span
            }
        }
    }
}

# View recent audit events (tail)
#
# @param --count: Number of recent events to show (default: 20)
# @param --follow: Follow new events in real-time
#
# @example View last 50 events
#   audit tail --count 50
#
# @example Follow audit log in real-time
#   audit tail --follow
export def "audit tail" [
    --count: int = 20             # Number of events to show
    --follow                      # Follow new events
] {
    if $follow {
        # Real-time following via WebSocket
        let orchestrator_url = get_orchestrator_url
        let ws_url = ($orchestrator_url | str replace "http" "ws")

        print "Following audit log (Ctrl+C to stop)..."
        # TODO: Implement WebSocket streaming
        print "WebSocket streaming not yet implemented"
    } else {
        # Show recent events
        audit query --limit $count --sort-by timestamp --sort-desc --out table
    }
}

# Search audit logs with text query
#
# @param query: Search text
# @param --field: Field to search (user, resource, action)
#
# @example Search for specific server
#   audit search "server-123"
#
# @example Search in specific field
#   audit search "john" --field user
export def "audit search" [
    query: string                 # Search query
    --field: string = "all"       # Field to search
] {
    # Use orchestrator search endpoint
    let orchestrator_url = get_orchestrator_url
    let response = http post $"($orchestrator_url)/api/v1/audit/search" {
        query: $query
        field: $field
    }

    if ($response | get success) {
        let results = ($response | get data)
        $results | select event_id timestamp user.id action.action_type action.resource
            | rename event_id timestamp user action resource
            | table
    } else {
        error make {
            msg: "Failed to search audit logs"
            label: {
                text: ($response | get error)
                span: (metadata $response).span
            }
        }
    }
}

# Helper: Get orchestrator URL from config
def get_orchestrator_url [] {
    # Try environment variable first
    let env_url = ($env.PROVISIONING_ORCHESTRATOR_URL? | default "")

    if ($env_url | is-not-empty) {
        $env_url
    } else {
        # Default to localhost
        "http://localhost:8080"
    }
}

# Helper: Parse relative date (1d, 7d, 1w, 1M, 1y)
def parse_relative_date [relative: string] {
    let now = (date now)

    if ($relative | str ends-with "d") {
        let days = ($relative | str replace "d" "" | into int)
        $now | date subtract ($days) day | format date "%+"
    } else if ($relative | str ends-with "w") {
        let weeks = ($relative | str replace "w" "" | into int)
        $now | date subtract ($weeks * 7) day | format date "%+"
    } else if ($relative | str ends-with "M") {
        let months = ($relative | str replace "M" "" | into int)
        $now | date subtract ($months) month | format date "%+"
    } else if ($relative | str ends-with "y") {
        let years = ($relative | str replace "y" "" | into int)
        $now | date subtract ($years) year | format date "%+"
    } else {
        # Assume it's already RFC3339
        $relative
    }
}

# Helper: Format bytes to human-readable
def format_bytes [bytes: int] {
    if $bytes < 1024 {
        $"($bytes) B"
    } else if $bytes < (1024 * 1024) {
        $"(($bytes / 1024) | math round -p 2) KB"
    } else if $bytes < (1024 * 1024 * 1024) {
        $"(($bytes / 1024 / 1024) | math round -p 2) MB"
    } else {
        $"(($bytes / 1024 / 1024 / 1024) | math round -p 2) GB"
    }
}

# Helper: Test if value is empty
def "is-empty" [] {
    $in == null or $in == ""
}

# Helper: Test if value is not empty
def "is-not-empty" [] {
    not ($in | is-empty)
}
