#!/usr/bin/env bash
# dashboard-validate: Validate a dashboard JSON file
#
# Usage: dashboard-validate <path-to-json> [--strict]
#
# Checks:
#   1. Valid JSON structure
#   2. Required fields present (name, owner, charts, layout)
#   3. All charts have an id field
#   4. No duplicate chart IDs
#   5. Chart IDs match layout IDs
#   6. LogStream queries have take limits
#   7. Grid layout doesn't exceed 12 columns
#
# Options:
#   --strict  Treat warnings as errors
#
# Examples:
#   dashboard-validate ./dashboard.json
#   dashboard-validate ./dashboard.json --strict

set -uo pipefail

STRICT=false
FILE=""

for arg in "$@"; do
    case $arg in
        --strict)
            STRICT=true
            ;;
        *)
            FILE="$arg"
            ;;
    esac
done

if [[ -z "$FILE" ]]; then
    echo "Usage: dashboard-validate <path-to-json> [--strict]"
    exit 2
fi

if [[ ! -f "$FILE" ]]; then
    echo "Error: File not found: $FILE"
    exit 2
fi

errors=0
warnings=0

error() {
    echo "ERROR: $1"
    errors=$((errors + 1))
}

warn() {
    echo "WARN: $1"
    warnings=$((warnings + 1))
}

info() {
    echo "INFO: $1"
}

# 1. Check valid JSON
if ! jq empty "$FILE" 2>/dev/null; then
    echo "ERROR: Invalid JSON"
    exit 1
fi
info "Valid JSON structure"

# 2. Check required fields
for field in name owner; do
    if [[ $(jq -r ".$field // empty" "$FILE") == "" ]]; then
        error "Missing required field: $field"
    fi
done

# 3. Check charts array exists
if [[ $(jq -r '.charts // "null"' "$FILE") == "null" ]]; then
    error "Missing charts array"
fi

# 4. Check layout array exists
if [[ $(jq -r '.layout // "null"' "$FILE") == "null" ]]; then
    error "Missing layout array"
fi

# 5. Check all charts have an id field
missing_ids=$(jq -r '.charts | to_entries[] | select(.value.id == null or .value.id == "") | .key' "$FILE" 2>/dev/null || true)
if [[ -n "$missing_ids" ]]; then
    for idx in $missing_ids; do
        chart_name=$(jq -r ".charts[$idx].name // \"(unnamed)\"" "$FILE")
        error "Chart at index $idx ($chart_name) is missing required 'id' field"
    done
fi

# 6. Check for duplicate chart IDs
duplicate_ids=$(jq -r '[.charts[].id // empty] | group_by(.) | map(select(length > 1) | .[0]) | .[]' "$FILE" 2>/dev/null | sort -u || true)
if [[ -n "$duplicate_ids" ]]; then
    for dup_id in $duplicate_ids; do
        error "Duplicate chart id: '$dup_id'"
    done
fi

# 7. Check chart IDs match layout IDs
chart_ids=$(jq -r '.charts[].id // empty' "$FILE" 2>/dev/null | sort)
layout_ids=$(jq -r '.layout[].i' "$FILE" 2>/dev/null | sort)

if [[ "$chart_ids" != "$layout_ids" ]]; then
    error "Chart IDs and layout IDs don't match"
    echo "  Charts: $(echo $chart_ids | tr '\n' ' ')"
    echo "  Layout: $(echo $layout_ids | tr '\n' ' ')"
fi

# 8. Check LogStream queries for take limits
logstream_without_take=$(jq -r '.charts[] | select(.type == "LogStream") | select(.query.apl != null) | select(.query.apl | test("take ") | not) | .id' "$FILE" 2>/dev/null || true)
if [[ -n "$logstream_without_take" ]]; then
    for id in $logstream_without_take; do
        warn "LogStream '$id' may be missing 'take N' limit"
    done
fi

# 9. Check grid width (should be 12 columns max)
max_right=$(jq '[.layout[] | (.x + .w)] | max // 0' "$FILE" 2>/dev/null || echo 0)
if [[ "$max_right" -gt 12 ]]; then
    warn "Layout exceeds 12-column grid (max right edge = $max_right)"
fi

# 10. Check schemaVersion
schema_version=$(jq -r '.schemaVersion // 0' "$FILE")
if [[ "$schema_version" != "2" ]]; then
    warn "schemaVersion is $schema_version, expected 2"
fi

# 11. Check layout entries have minH/minW
missing_min=$(jq -r '.layout[] | select(.minH == null or .minW == null) | .i' "$FILE" 2>/dev/null || true)
if [[ -n "$missing_min" ]]; then
    info "$(echo "$missing_min" | wc -l | tr -d ' ') layout entries missing minH/minW (will be auto-fixed on deploy)"
fi

# Summary
echo ""
echo "Validation complete: $errors errors, $warnings warnings"

if [[ $errors -gt 0 ]]; then
    exit 1
fi

if [[ "$STRICT" == "true" && $warnings -gt 0 ]]; then
    exit 1
fi

exit 0
