#!/bin/bash
# =============================================================================
# Phase 5: Public Integration Test Suite
# =============================================================================
# Validates end-to-end user flows through public API endpoints
# to ensure frontend integration works correctly.
#
# Story: GALA-TEST-5
# Risk Mitigation: R3 (Route Breaking Changes), R4 (Collections/Images Untested)
#
# Test Coverage:
#   - Flow 1: Event Discovery (5 endpoints) - 15 tests
#   - Flow 2: Booking Flow (5 endpoints) - 15 tests
#   - Flow 3: Newsletter Flow (2 endpoints) - 4 tests
#   Total: 34 tests
#
# Date: 2026-01-20
# =============================================================================

# Don't exit on errors - we need to continue testing and report all failures
# set -e

# Configuration
API_BASE="http://localhost:8100/api"
RESULTS_FILE="/tmp/phase5_public_integration_results.txt"
TEST_EVENT_SLUG="mohamed-abdo-new-years-celebration-2025"
TEST_EMAIL="test+$(date +%s)@example.com"

# Counters
PASSED=0
FAILED=0
TOTAL_TESTS=0

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# =============================================================================
# Helper Functions
# =============================================================================

log_header() {
    echo ""
    echo "=== $1 ===" | tee -a "$RESULTS_FILE"
}

log_test() {
    echo -n "  [$((TOTAL_TESTS + 1))] $1 ... "
}

log_pass() {
    echo -e "${GREEN}PASS${NC}"
    echo "  [PASS] $1" >> "$RESULTS_FILE"
    ((PASSED++))
    ((TOTAL_TESTS++))
}

log_fail() {
    echo -e "${RED}FAIL${NC} - $1"
    echo "  [FAIL] $2 - $1" >> "$RESULTS_FILE"
    ((FAILED++))
    ((TOTAL_TESTS++))
}

# Initialize results file
init_results() {
    echo "==============================================================================" > "$RESULTS_FILE"
    echo "Phase 5: Public Integration Test Suite" >> "$RESULTS_FILE"
    echo "==============================================================================" >> "$RESULTS_FILE"
    echo "Date: $(date)" >> "$RESULTS_FILE"
    echo "API Base: $API_BASE" >> "$RESULTS_FILE"
    echo "Test Event: $TEST_EVENT_SLUG" >> "$RESULTS_FILE"
    echo "" >> "$RESULTS_FILE"
}

# Generic API call function
api_call() {
    local method=$1
    local endpoint=$2
    local data=$3
    local headers=$4

    local curl_args=(-s -w "\n%{http_code}")

    # Add method
    if [ "$method" != "GET" ]; then
        curl_args+=(-X "$method")
    fi

    # Add content type for POST/PUT
    if [ "$method" = "POST" ] || [ "$method" = "PUT" ]; then
        curl_args+=(-H "Content-Type: application/json")
    fi

    # Add custom headers
    if [ -n "$headers" ]; then
        IFS=';' read -ra HEADER_ARRAY <<< "$headers"
        for header in "${HEADER_ARRAY[@]}"; do
            curl_args+=(-H "$header")
        done
    fi

    # Add data for POST/PUT/DELETE
    if [ -n "$data" ]; then
        curl_args+=(-d "$data")
    fi

    # Execute curl
    curl "${curl_args[@]}" "${API_BASE}${endpoint}"
}

# Check if response contains expected value
assert_contains() {
    local response=$1
    local expected=$2
    local test_name=$3

    log_test "$test_name"

    if echo "$response" | grep -q "$expected"; then
        log_pass "$test_name"
        return 0
    else
        log_fail "Expected to contain '$expected'" "$test_name"
        return 1
    fi
}

# Check if JSON field exists (works for null, false, empty values)
assert_field_exists() {
    local response=$1
    local field=$2
    local test_name=$3

    log_test "$test_name"

    # Use jq to check if field path exists (returns field type, not value)
    if echo "$response" | jq -e "$field | type" > /dev/null 2>&1; then
        log_pass "$test_name"
        return 0
    else
        log_fail "Field '$field' not found" "$test_name"
        return 1
    fi
}

# Check if JSON field has expected value
assert_field_value() {
    local response=$1
    local field=$2
    local expected=$3
    local test_name=$4

    log_test "$test_name"

    local actual
    actual=$(echo "$response" | jq -r "$field" 2>/dev/null)

    if [ "$actual" = "$expected" ]; then
        log_pass "$test_name"
        return 0
    else
        log_fail "Expected '$expected', got '$actual'" "$test_name"
        return 1
    fi
}

# Check HTTP status code
assert_status() {
    local response=$1
    local expected_status=$2
    local test_name=$3

    log_test "$test_name"

    local status
    status=$(echo "$response" | tail -n 1)

    if [ "$status" = "$expected_status" ]; then
        log_pass "$test_name"
        return 0
    else
        log_fail "Expected status $expected_status, got $status" "$test_name"
        return 1
    fi
}

# Check response is valid JSON
assert_valid_json() {
    local response=$1
    local test_name=$2

    log_test "$test_name"

    local body
    body=$(echo "$response" | sed '$d')

    if echo "$body" | jq empty 2>/dev/null; then
        log_pass "$test_name"
        return 0
    else
        log_fail "Invalid JSON response" "$test_name"
        return 1
    fi
}

# Check if array is not empty
assert_array_not_empty() {
    local response=$1
    local field=$2
    local test_name=$3

    log_test "$test_name"

    local body
    body=$(echo "$response" | sed '$d')
    local length
    length=$(echo "$body" | jq "$field | length" 2>/dev/null)

    if [ -n "$length" ] && [ "$length" -gt 0 ]; then
        log_pass "$test_name"
        return 0
    else
        log_fail "Array '$field' is empty or not found (length: $length)" "$test_name"
        return 1
    fi
}

# Get body from response (strips status code)
get_body() {
    echo "$1" | sed '$d'
}

# Get status from response
get_status() {
    echo "$1" | tail -n 1
}

# =============================================================================
# Flow 1: Event Discovery
# =============================================================================
# Tests the public event browsing and detail viewing flow
# Endpoints: /events, /events/{slug}, /events/{slug}/images,
#            /events/{slug}/collection, /events/{slug}/venue

test_flow_1_event_discovery() {
    log_header "Flow 1: Event Discovery (5 endpoints)"

    local response body status event_slug

    # -------------------------------------------------------------------------
    # Step 1: List events
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 1: List events"

    response=$(api_call "GET" "/events")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 1.1: Events endpoint returns 200
    assert_status "$response" "200" "Events list returns 200"

    # Test 1.2: Response has success:true
    assert_field_value "$body" ".success" "true" "Events list has success:true"

    # Test 1.3: Response has data array
    assert_field_exists "$body" ".data" "Events list has data array"

    # -------------------------------------------------------------------------
    # Step 2: View event detail
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 2: View event detail"

    response=$(api_call "GET" "/events/$TEST_EVENT_SLUG")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 1.4: Event detail returns 200
    assert_status "$response" "200" "Event detail returns 200"

    # Test 1.5: Event has id
    assert_field_exists "$body" ".data.id" "Event has id"

    # Test 1.6: Event has name
    assert_field_exists "$body" ".data.name" "Event has name"

    # Test 1.7: Event has slug
    assert_field_exists "$body" ".data.slug" "Event has slug"

    # -------------------------------------------------------------------------
    # Step 3: Load images
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 3: Load event images"

    response=$(api_call "GET" "/events/$TEST_EVENT_SLUG/images")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 1.8: Images endpoint returns 200
    assert_status "$response" "200" "Images endpoint returns 200"

    # Test 1.9: Response has success field
    assert_field_exists "$body" ".success" "Images response has success field"

    # Test 1.10: Response has data field
    assert_field_exists "$body" ".data" "Images response has data field"

    # -------------------------------------------------------------------------
    # Step 4: Load collection (videos)
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 4: Load event collection (videos)"

    response=$(api_call "GET" "/events/$TEST_EVENT_SLUG/collection")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 1.11: Collection endpoint returns 200
    assert_status "$response" "200" "Collection endpoint returns 200"

    # Test 1.12: Response has success field
    assert_field_exists "$body" ".success" "Collection response has success field"

    # -------------------------------------------------------------------------
    # Step 5: View venue
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 5: View event venue"

    response=$(api_call "GET" "/events/$TEST_EVENT_SLUG/venue")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 1.13: Venue endpoint returns 200 or 500 (no venue assigned is acceptable)
    log_test "Venue endpoint returns valid status (200 or 500)"
    if [ "$status" = "200" ] || [ "$status" = "500" ]; then
        log_pass "Venue endpoint returns valid status (200 or 500)"
    else
        log_fail "Expected 200 or 500, got $status" "Venue endpoint returns valid status"
    fi

    # Test 1.14: Response is valid JSON
    assert_valid_json "$response" "Venue response is valid JSON"

    # Test 1.15: If 200, response has success field
    if [ "$status" = "200" ]; then
        assert_field_exists "$body" ".success" "Venue response has success field"
    else
        log_test "Venue response has error message (500 case)"
        if echo "$body" | jq -e '.message' > /dev/null 2>&1; then
            log_pass "Venue response has error message (500 case)"
        else
            log_fail "Missing error message" "Venue response has error message (500 case)"
        fi
    fi

    echo ""
    echo "  Flow 1 Summary: Event discovery flow complete"
}

# =============================================================================
# Flow 2: Booking Flow
# =============================================================================
# Tests the seat booking user journey
# Endpoints: /events/{slug}/availability, /events/{slug}/tiers,
#            /seats/hold, /seats/confirm, /orders/deposit

test_flow_2_booking_flow() {
    log_header "Flow 2: Booking Flow (5 endpoints)"

    local response body status event_id seat_id hold_token

    # -------------------------------------------------------------------------
    # Step 1: Check availability
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 1: Check seat availability"

    response=$(api_call "GET" "/events/$TEST_EVENT_SLUG/availability")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 2.1: Availability endpoint returns valid status (200 or 500 if no venue)
    log_test "Availability endpoint returns valid status (200 or 500)"
    if [ "$status" = "200" ] || [ "$status" = "500" ]; then
        log_pass "Availability endpoint returns valid status (200 or 500)"
    else
        log_fail "Expected 200 or 500, got $status" "Availability endpoint returns valid status"
    fi

    # Test 2.2: Response is valid JSON
    assert_valid_json "$response" "Availability response is valid JSON"

    # Test 2.3: Response has success field
    assert_field_exists "$body" ".success" "Availability has success field"

    # Extract a seat_id and event_id for later tests (if available)
    if [ "$status" = "200" ]; then
        seat_id=$(echo "$body" | jq -r '.data[0].db_seat_id // .data[0].seat_id // empty' 2>/dev/null)
        event_id=$(echo "$body" | jq -r '.data[0].event_id // empty' 2>/dev/null)
    fi

    # -------------------------------------------------------------------------
    # Step 2: Get price tiers
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 2: Get price tiers"

    response=$(api_call "GET" "/events/$TEST_EVENT_SLUG/tiers")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 2.4: Tiers endpoint returns 200
    assert_status "$response" "200" "Tiers endpoint returns 200"

    # Test 2.5: Response has success:true
    assert_field_value "$body" ".success" "true" "Tiers has success:true"

    # Test 2.6: Response has data array
    assert_field_exists "$body" ".data" "Tiers has data array"

    # -------------------------------------------------------------------------
    # Step 3: Hold seats (test validation)
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 3: Hold seats (testing validation)"

    # Generate session ID
    local session_id="test-session-$(date +%s)"

    # Test with invalid seat ID to verify endpoint responds correctly
    local hold_data='{"event_id": 1, "seat_ids": ["invalid-seat-id"], "session_id": "'$session_id'"}'

    response=$(api_call "POST" "/seats/hold" "$hold_data")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 2.7: Hold endpoint returns valid status (200, 201, 409, or 422)
    log_test "Hold endpoint returns valid status"
    if [ "$status" = "200" ] || [ "$status" = "201" ] || [ "$status" = "409" ] || [ "$status" = "422" ]; then
        log_pass "Hold endpoint returns valid status"
    else
        log_fail "Expected 200/201/409/422, got $status" "Hold endpoint returns valid status"
    fi

    # Test 2.8: Response is valid JSON
    assert_valid_json "$response" "Hold response is valid JSON"

    # Test 2.9: Response has success field
    assert_field_exists "$body" ".success" "Hold response has success field"

    # -------------------------------------------------------------------------
    # Step 4: Confirm booking (expects 400 without idempotency header)
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 4: Confirm booking (testing idempotency requirement)"

    # Test without idempotency header - should return 400
    local confirm_data='{"hold_id": "test-hold-123"}'
    response=$(api_call "POST" "/seats/confirm" "$confirm_data")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 2.10: Confirm without idempotency returns 400
    assert_status "$response" "400" "Confirm without idempotency returns 400"

    # Test 2.11: Error response has success:false
    assert_field_value "$body" ".success" "false" "Confirm error has success:false"

    # Test 2.12: Error response has message
    assert_field_exists "$body" ".message" "Confirm error has message"

    # -------------------------------------------------------------------------
    # Step 5: Create deposit order (testing idempotency requirement)
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 5: Create deposit order (testing idempotency requirement)"

    # Test without idempotency header - should return 400
    local deposit_data='{"hold_id": "test-hold-123", "amount": 100}'
    response=$(api_call "POST" "/orders/deposit" "$deposit_data")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 2.13: Deposit without idempotency returns 400
    assert_status "$response" "400" "Deposit without idempotency returns 400"

    # Test 2.14: Error response is valid JSON
    assert_valid_json "$response" "Deposit error is valid JSON"

    # Test 2.15: Error response has success:false
    assert_field_value "$body" ".success" "false" "Deposit error has success:false"

    echo ""
    echo "  Flow 2 Summary: Booking flow complete"
}

# =============================================================================
# Flow 3: Newsletter Flow
# =============================================================================
# Tests newsletter subscription and unsubscription
# Endpoints: /newsletter/subscribe, /newsletter/unsubscribe

test_flow_3_newsletter_flow() {
    log_header "Flow 3: Newsletter Flow (2 endpoints)"

    local response body status subscription_token

    # -------------------------------------------------------------------------
    # Step 1: Subscribe to newsletter
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 1: Subscribe to newsletter"

    local subscribe_data=$(cat <<EOF
{
    "email": "$TEST_EMAIL",
    "name": "Test User",
    "consent_marketing": true
}
EOF
)

    response=$(api_call "POST" "/newsletter/subscribe" "$subscribe_data")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 3.1: Subscribe endpoint returns valid status (200, 201, 422, or 429)
    log_test "Subscribe endpoint returns valid status"
    if [ "$status" = "200" ] || [ "$status" = "201" ] || [ "$status" = "422" ] || [ "$status" = "429" ]; then
        log_pass "Subscribe endpoint returns valid status"
    else
        log_fail "Expected 200/201/422/429, got $status" "Subscribe endpoint returns valid status"
    fi

    # Test 3.2: Response is valid JSON
    assert_valid_json "$response" "Subscribe response is valid JSON"

    # Extract subscription token for unsubscribe test
    if [ "$status" = "200" ] || [ "$status" = "201" ]; then
        subscription_token=$(echo "$body" | jq -r '.data.subscription_token // empty' 2>/dev/null)
    fi

    # -------------------------------------------------------------------------
    # Step 2: Unsubscribe from newsletter
    # -------------------------------------------------------------------------
    echo ""
    echo "  Step 2: Unsubscribe from newsletter"

    # Use the subscription token if available, otherwise test validation error
    local unsubscribe_data
    if [ -n "$subscription_token" ]; then
        unsubscribe_data="{\"token\": \"$subscription_token\"}"
    else
        unsubscribe_data="{\"token\": \"invalid-token-for-test\"}"
    fi

    response=$(api_call "POST" "/newsletter/unsubscribe" "$unsubscribe_data")
    status=$(get_status "$response")
    body=$(get_body "$response")

    # Test 3.3: Unsubscribe endpoint returns valid status (200, 404, 422, or 429)
    log_test "Unsubscribe endpoint returns valid status"
    if [ "$status" = "200" ] || [ "$status" = "404" ] || [ "$status" = "422" ] || [ "$status" = "429" ]; then
        log_pass "Unsubscribe endpoint returns valid status"
    else
        log_fail "Expected 200/404/422/429, got $status" "Unsubscribe endpoint returns valid status"
    fi

    # Test 3.4: Response is valid JSON
    assert_valid_json "$response" "Unsubscribe response is valid JSON"

    echo ""
    echo "  Flow 3 Summary: Newsletter flow complete"
}

# =============================================================================
# Main Execution
# =============================================================================

main() {
    echo "=============================================================================="
    echo "Phase 5: Public Integration Test Suite"
    echo "=============================================================================="
    echo "Date: $(date)"
    echo "API Base: $API_BASE"
    echo "Test Event: $TEST_EVENT_SLUG"
    echo ""

    # Initialize results file
    init_results

    # Check API availability
    echo "Checking API availability..."
    if ! curl -s --connect-timeout 5 "$API_BASE/events" > /dev/null 2>&1; then
        echo -e "${RED}ERROR: API not reachable at $API_BASE${NC}"
        echo "Please ensure Laravel server is running on port 8100"
        exit 1
    fi
    echo -e "${GREEN}API is available${NC}"
    echo ""

    # Run test flows
    test_flow_1_event_discovery
    test_flow_2_booking_flow
    test_flow_3_newsletter_flow

    # Summary
    echo ""
    echo "=============================================================================="
    echo "TEST SUMMARY"
    echo "=============================================================================="
    echo "Total Tests: $TOTAL_TESTS"
    echo -e "Passed: ${GREEN}$PASSED${NC}"
    echo -e "Failed: ${RED}$FAILED${NC}"
    echo ""

    # Write summary to results file
    echo "" >> "$RESULTS_FILE"
    echo "==============================================================================" >> "$RESULTS_FILE"
    echo "TEST SUMMARY" >> "$RESULTS_FILE"
    echo "==============================================================================" >> "$RESULTS_FILE"
    echo "Total Tests: $TOTAL_TESTS" >> "$RESULTS_FILE"
    echo "Passed: $PASSED" >> "$RESULTS_FILE"
    echo "Failed: $FAILED" >> "$RESULTS_FILE"
    echo "" >> "$RESULTS_FILE"

    # Final result
    if [ $FAILED -eq 0 ]; then
        echo -e "${GREEN}ALL TESTS PASSED!${NC}"
        echo "Results saved to: $RESULTS_FILE"
        exit 0
    else
        echo -e "${YELLOW}Some tests failed. Review results above.${NC}"
        echo "Results saved to: $RESULTS_FILE"
        exit 1
    fi
}

# Run main
main "$@"
