// Copyright (c) 2026 Alibaba Group and its affiliates

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

//     http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package tdx

import (
	"encoding/binary"
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"
)

// Helper function to load a test quote from testdata
func loadTestQuoteData(t *testing.T, filename string) []byte {
	t.Helper()
	quotePath := filepath.Join("testdata", "quote", filename)
	quoteData, err := os.ReadFile(quotePath)
	if err != nil {
		t.Fatalf("Failed to read test quote %s: %v", filename, err)
	}
	return quoteData
}

func TestParseQuoteWithEmptyData(t *testing.T) {
	_, err := ParseQuote([]byte{})
	if err == nil {
		t.Fatal("Expected error when parsing empty data")
	}
	if !strings.Contains(err.Error(), "quote too short to be parsed") {
		t.Errorf("Expected 'quote too short to be parsed' error, got: %v", err)
	}
}

func TestParseQuoteWithInsufficientData(t *testing.T) {
	shortData := []byte("short")
	_, err := ParseQuote(shortData)
	if err == nil {
		t.Fatal("Expected error when parsing short data")
	}
	if !strings.Contains(err.Error(), "quote too short to be parsed") {
		t.Errorf("Expected 'quote too short to be parsed' error, got: %v", err)
	}
}

func TestParseQuoteWithInvalidVersion(t *testing.T) {
	// Use real quote and modify version to invalid value
	quoteData := loadTestQuoteData(t, "tdx_quote_4.dat")
	modifiedQuote := make([]byte, len(quoteData))
	copy(modifiedQuote, quoteData)
	binary.LittleEndian.PutUint16(modifiedQuote[0:2], 2) // Any invalid version (not 3/4/5)

	_, err := ParseQuote(modifiedQuote)
	if err == nil {
		t.Fatal("Expected error for invalid version")
	}
	if !strings.Contains(err.Error(), "unsupported quote version") {
		t.Errorf("Expected 'unsupported quote version' error, got: %v", err)
	}
}

func TestParseQuoteWithInvalidAttestationKeyType(t *testing.T) {
	quoteData := loadTestQuoteData(t, "tdx_quote_4.dat")
	modifiedQuote := make([]byte, len(quoteData))
	copy(modifiedQuote, quoteData)
	binary.LittleEndian.PutUint16(modifiedQuote[2:4], 99) // Invalid key type

	_, err := ParseQuote(modifiedQuote)
	if err == nil {
		t.Fatal("Expected error for invalid attestation key type")
	}
	if !strings.Contains(err.Error(), "unsupported attestation key type") {
		t.Errorf("Expected 'unsupported attestation key type' error, got: %v", err)
	}
}

func TestParseQuoteWithInvalidTEEType(t *testing.T) {
	quoteData := loadTestQuoteData(t, "tdx_quote_4.dat")
	modifiedQuote := make([]byte, len(quoteData))
	copy(modifiedQuote, quoteData)
	binary.LittleEndian.PutUint32(modifiedQuote[4:8], 0x99) // Invalid TEE type

	_, err := ParseQuote(modifiedQuote)
	if err == nil {
		t.Fatal("Expected error for invalid TEE type")
	}
	if !strings.Contains(err.Error(), "unsupported TEE type") {
		t.Errorf("Expected 'unsupported TEE type' error, got: %v", err)
	}
}

func TestParseQuoteWithValidTDXQuotes(t *testing.T) {
	// Test with real TDX quote files
	quoteFiles := []string{
		"tdx_quote_4.dat",
		"tdx_quote_5.dat",
		"tdx_quote_5_2.dat",
		"tdx_quote_pai.dat",
	}

	for _, filename := range quoteFiles {
		t.Run(filename, func(t *testing.T) {
			quotePath := filepath.Join("testdata", "quote", filename)
			if _, err := os.Stat(quotePath); os.IsNotExist(err) {
				t.Skipf("Test data file not found: %s", quotePath)
			}

			quoteData, err := os.ReadFile(quotePath)
			if err != nil {
				t.Fatalf("Failed to read test quote file: %v", err)
			}

			// Parse quote using ParseQuote API
			parsedQuote, err := ParseQuote(quoteData)
			if err != nil {
				t.Errorf("Failed to parse quote %s: %v", filename, err)
				return
			}

			// Verify basic information
			if parsedQuote.Header.Version == 0 {
				t.Error("Quote version should not be 0")
			}

			if parsedQuote.Header.TeeType != TEE_TYPE_TDX {
				t.Errorf("Expected TEE type to be TDX (0x%x), got 0x%x", TEE_TYPE_TDX, parsedQuote.Header.TeeType)
			}

			// Use type assertion to access report data
			var reportData []byte
			var reportType string
			var mrtdHex string

			switch report := parsedQuote.Report.(type) {
			case EnclaveReportBody:
				reportData = report.ReportData[:]
				reportType = "SGX Enclave Report"
			case TdReport10:
				reportData = report.ReportData[:]
				reportType = "TD Report 1.0"
				mrtdHex = fmt.Sprintf("%x", report.MrTd[:])
			case TdReport15:
				reportData = report.ReportData[:]
				reportType = "TD Report 1.5"
				mrtdHex = fmt.Sprintf("%x", report.MrTd[:])
			}

			if len(reportData) != 64 {
				t.Errorf("Expected report data to be 64 bytes, got %d", len(reportData))
			}

			t.Logf("Successfully parsed %s:", filename)
			t.Logf("  Version: %d", parsedQuote.Header.Version)
			t.Logf("  TEE Type: 0x%x", parsedQuote.Header.TeeType)
			t.Logf("  Report Type: %s", reportType)
			t.Logf("  Report Data: %x", reportData)
			if parsedQuote.Header.TeeType == TEE_TYPE_TDX && mrtdHex != "" {
				t.Logf("  MRTD: %s", mrtdHex)
			}
		})
	}
}
