#!/bin/bash

# End-to-End Test Script for KMS API
# This script tests the Key Management Service API using curl commands

# set -e  # Exit on any error - commented out for debugging

# Configuration
BASE_URL="${BASE_URL:-http://localhost:8080}"
API_BASE="${BASE_URL}/api"
USER_EMAIL="${USER_EMAIL:-test@example.com}"
USER_ID="${USER_ID:-test-user-123}"

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

# Test counters
TESTS_RUN=0
TESTS_PASSED=0
TESTS_FAILED=0

# Helper functions
log_info() {
    echo -e "${BLUE}[INFO]${NC} $1"
}

log_success() {
    echo -e "${GREEN}[PASS]${NC} $1"
    ((TESTS_PASSED++))
}

log_error() {
    echo -e "${RED}[FAIL]${NC} $1"
    ((TESTS_FAILED++))
}

log_warning() {
    echo -e "${YELLOW}[WARN]${NC} $1"
}

run_test() {
    local test_name="$1"
    local expected_status="$2"
    shift 2
    local curl_args=("$@")
    
    ((TESTS_RUN++))
    log_info "Running test: $test_name"
    
    # Run curl command and capture response
    local response
    local status_code
    
    response=$(curl -s -w "\n%{http_code}" "${curl_args[@]}" 2>/dev/null || echo -e "\n000")
    status_code=$(echo "$response" | tail -n1)
    local body=$(echo "$response" | head -n -1)
    
    if [[ "$status_code" == "$expected_status" ]]; then
        log_success "$test_name (Status: $status_code)"
        if [[ -n "$body" && "$body" != "null" && "$body" != "" ]]; then
            echo "  Response: $body" | head -c 300
            if [[ ${#body} -gt 300 ]]; then
                echo "..."
            fi
            echo
        else
            echo "  Response: (empty or null)"
        fi
        return 0
    else
        log_error "$test_name (Expected: $expected_status, Got: $status_code)"
        if [[ -n "$body" ]]; then
            echo "Response: $body"
        fi
        return 1
    fi
}

# Wait for server to be ready
wait_for_server() {
    log_info "Waiting for server to be ready..."
    local max_attempts=30
    local attempt=1
    
    while [[ $attempt -le $max_attempts ]]; do
        if curl -s "$BASE_URL/health" > /dev/null 2>&1; then
            log_success "Server is ready!"
            return 0
        fi
        log_info "Attempt $attempt/$max_attempts - Server not ready, waiting..."
        sleep 2
        ((attempt++))
    done
    
    log_error "Server failed to start within timeout"
    exit 1
}

# Test functions
test_health_endpoints() {
    log_info "=== Testing Health Endpoints ==="
    
    run_test "Health Check" "200" \
        -X GET "$BASE_URL/health"
    
    run_test "Readiness Check" "200" \
        -X GET "$BASE_URL/ready"
}

test_authentication_endpoints() {
    log_info "=== Testing Authentication Endpoints ==="
    
    # Test login without auth headers (should fail)
    run_test "Login without auth headers" "401" \
        -X POST "$API_BASE/login" \
        -H "Content-Type: application/json" \
        -d '{
            "app_id": "test-app-123",
            "permissions": ["read", "write"],
            "redirect_uri": "https://example.com/callback"
        }'
    
    # Test login with auth headers
    run_test "Login with auth headers" "200" \
        -X POST "$API_BASE/login" \
        -H "Content-Type: application/json" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID" \
        -d '{
            "app_id": "test-app-123",
            "permissions": ["read", "write"]
        }'
    
    # Test verify endpoint
    run_test "Verify token" "200" \
        -X POST "$API_BASE/verify" \
        -H "Content-Type: application/json" \
        -d '{
            "app_id": "test-app-123",
            "token": "test-token-123",
            "type": "static"
        }'
    
    # Test renew endpoint
    run_test "Renew token" "200" \
        -X POST "$API_BASE/renew" \
        -H "Content-Type: application/json" \
        -d '{
            "app_id": "test-app-123",
            "user_id": "test-user-123",
            "token": "test-token-123"
        }'
}

test_application_endpoints() {
    log_info "=== Testing Application Endpoints ==="
    
    # Test list applications without auth (should fail)
    run_test "List applications without auth" "401" \
        -X GET "$API_BASE/applications"
    
    # Test list applications with auth
    run_test "List applications with auth" "200" \
        -X GET "$API_BASE/applications" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID"
    
    # Test list applications with pagination
    run_test "List applications with pagination" "200" \
        -X GET "$API_BASE/applications?limit=10&offset=0" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID"
    
    # Generate unique application ID
    local unique_app_id="test-app-e2e-$(date +%s%N | cut -b1-13)-$RANDOM"
    
    # Test create application
    run_test "Create application" "201" \
        -X POST "$API_BASE/applications" \
        -H "Content-Type: application/json" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID" \
        -d '{
            "app_id": "'$unique_app_id'",
            "app_link": "https://example.com/test-app",
            "type": ["static"],
            "callback_url": "https://example.com/callback",
            "token_renewal_duration": 604800000000000,
            "max_token_duration": 2592000000000000,
            "owner": {
                "type": "individual",
                "name": "Test User",
                "owner": "test@example.com"
            }
        }'
    
    # Use the unique_app_id directly since we know it was created successfully
    local app_id="$unique_app_id"
    
    if [[ -n "$app_id" && "$app_id" != "test-app-123" ]]; then
        log_info "Using created app_id: $app_id"
        
        # Test get application by ID
        run_test "Get application by ID" "200" \
            -X GET "$API_BASE/applications/$app_id" \
            -H "X-User-Email: $USER_EMAIL" \
            -H "X-User-ID: $USER_ID"
        
        # Test update application
        run_test "Update application" "200" \
            -X PUT "$API_BASE/applications/$app_id" \
            -H "Content-Type: application/json" \
            -H "X-User-Email: $USER_EMAIL" \
            -H "X-User-ID: $USER_ID" \
            -d '{
                "name": "Updated Test Application",
                "description": "An updated test application"
            }'
        
        # Store app_id for token tests
        export TEST_APP_ID="$app_id"
    else
        log_warning "Could not extract app_id from create response, using default"
        export TEST_APP_ID="test-app-123"
    fi
    
    # Test get non-existent application
    run_test "Get non-existent application" "404" \
        -X GET "$API_BASE/applications/non-existent-id" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID"
    
    # Test create application with invalid JSON
    run_test "Create application with invalid JSON" "400" \
        -X POST "$API_BASE/applications" \
        -H "Content-Type: application/json" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID" \
        -d '{"invalid": json}'
}

test_token_endpoints() {
    log_info "=== Testing Token Endpoints ==="
    
    local app_id="${TEST_APP_ID:-test-app-123}"
    
    # Test list tokens for application
    run_test "List tokens for application" "200" \
        -X GET "$API_BASE/applications/$app_id/tokens" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID"
    
    # Test list tokens with pagination
    run_test "List tokens with pagination" "200" \
        -X GET "$API_BASE/applications/$app_id/tokens?limit=5&offset=0" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID"
    
    # Test create static token and capture response for token_id extraction
    local token_response
    token_response=$(curl -s -w "\n%{http_code}" -X POST "$API_BASE/applications/$app_id/tokens" \
        -H "Content-Type: application/json" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID" \
        -d '{
            "owner": {
                "type": "individual",
                "name": "Test Token Owner",
                "owner": "test-token@example.com"
            },
            "permissions": ["repo.read", "repo.write"]
        }' 2>/dev/null || echo -e "\n000")
    
    local token_status_code=$(echo "$token_response" | tail -n1)
    local token_body=$(echo "$token_response" | head -n -1)
    
    run_test "Create static token" "201" \
        -X POST "$API_BASE/applications/$app_id/tokens" \
        -H "Content-Type: application/json" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID" \
        -d '{
            "owner": {
                "type": "individual",
                "name": "Test Token Owner",
                "owner": "test-token@example.com"
            },
            "permissions": ["repo.read", "repo.write"]
        }'
    
    # Extract token_id from the first response for deletion test
    local token_id
    token_id=$(echo "$token_body" | grep -o '"id":"[^"]*"' | cut -d'"' -f4 || echo "")
    
    if [[ -n "$token_id" ]]; then
        log_info "Using created token_id: $token_id"
        
        # Test delete token
        run_test "Delete token" "204" \
            -X DELETE "$API_BASE/tokens/$token_id" \
            -H "X-User-Email: $USER_EMAIL" \
            -H "X-User-ID: $USER_ID"
    else
        log_warning "Could not extract token_id from create response"
    fi
    
    # Test create token with invalid JSON
    run_test "Create token with invalid JSON" "400" \
        -X POST "$API_BASE/applications/$app_id/tokens" \
        -H "Content-Type: application/json" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID" \
        -d '{"invalid": json}'
    
    # Test delete non-existent token
    run_test "Delete non-existent token" "500" \
        -X DELETE "$API_BASE/tokens/00000000-0000-0000-0000-000000000000" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID"
}

test_error_handling() {
    log_info "=== Testing Error Handling ==="
    
    # Test invalid endpoints
    run_test "Invalid endpoint" "404" \
        -X GET "$API_BASE/invalid-endpoint"
    
    # Test missing content-type for POST requests
    local unique_missing_ct_id="test-missing-ct-$(date +%s%N | cut -b1-13)-$RANDOM"
    run_test "Missing content-type" "400" \
        -X POST "$API_BASE/applications" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID" \
        -d '{
            "app_id": "'$unique_missing_ct_id'",
            "app_link": "https://example.com/test-app",
            "type": ["static"],
            "callback_url": "https://example.com/callback",
            "token_renewal_duration": 604800000000000,
            "max_token_duration": 2592000000000000,
            "owner": {
                "type": "individual",
                "name": "Test User",
                "owner": "test@example.com"
            }
        }'
    
    # Test malformed JSON
    run_test "Malformed JSON" "400" \
        -X POST "$API_BASE/applications" \
        -H "Content-Type: application/json" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID" \
        -d '{"name": "test"'
}

test_documentation_endpoint() {
    log_info "=== Testing Documentation Endpoint ==="
    
    run_test "Get API documentation" "200" \
        -X GET "$API_BASE/docs" \
        -H "X-User-Email: $USER_EMAIL" \
        -H "X-User-ID: $USER_ID"
}

cleanup_test_data() {
    log_info "=== Cleaning up test data ==="
    
    if [[ -n "${TEST_APP_ID:-}" && "$TEST_APP_ID" != "test-app-123" ]]; then
        log_info "Deleting test application: $TEST_APP_ID"
        curl -s -X DELETE "$API_BASE/applications/$TEST_APP_ID" \
            -H "X-User-Email: $USER_EMAIL" \
            -H "X-User-ID: $USER_ID" > /dev/null 2>&1 || true
    fi
}

print_summary() {
    echo
    log_info "=== Test Summary ==="
    echo "Tests Run: $TESTS_RUN"
    echo -e "Tests Passed: ${GREEN}$TESTS_PASSED${NC}"
    echo -e "Tests Failed: ${RED}$TESTS_FAILED${NC}"
    
    if [[ $TESTS_FAILED -eq 0 ]]; then
        echo -e "${GREEN}All tests passed!${NC}"
        exit 0
    else
        echo -e "${RED}Some tests failed!${NC}"
        exit 1
    fi
}

# Main execution
main() {
    log_info "Starting End-to-End Tests for KMS API"
    log_info "Base URL: $BASE_URL"
    log_info "User Email: $USER_EMAIL"
    log_info "User ID: $USER_ID"
    echo
    
    # Wait for server to be ready
    wait_for_server
    
    # Run all test suites
    test_health_endpoints
    echo
    
    test_authentication_endpoints
    echo
    
    test_application_endpoints
    echo
    
    test_token_endpoints
    echo
    
    test_error_handling
    echo
    
    test_documentation_endpoint
    echo
    
    # Cleanup
    cleanup_test_data
    
    # Print summary
    print_summary
}

# Handle script interruption
trap cleanup_test_data EXIT

# Check if curl is available
if ! command -v curl &> /dev/null; then
    log_error "curl is required but not installed"
    exit 1
fi

# Run main function
main "$@"
