/*
 * Copyright (c) 2026 Huawei Technologies Co., Ltd.
 * openFuyao is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package openscap

import (
	"testing"

	compliancev1alpha1 "gitcode.com/openFuyao/compliance-operator/api/v1alpha1"
	"gitcode.com/openFuyao/compliance-operator/pkg/unified"
)

func TestParser_Parse(t *testing.T) {
	tests := []struct {
		name        string
		rawOutput   string
		wantCount   int
		wantErr     bool
		checkResult *compliancev1alpha1.UnifiedCheckResult
	}{
		{
			name: "valid openscap output with markers",
			rawOutput: `Some logs before
===COMPLIANCE_RESULT_START===
<?xml version="1.0" encoding="UTF-8"?>
<TestResult xmlns="http://checklists.nist.gov/xccdf/1.2">
  <rule-result idref="xccdf_mil.disa.stig_rule_SV-242376r960759_rule" severity="medium">
    <result>pass</result>
  </rule-result>
  <rule-result idref="xccdf_mil.disa.stig_rule_SV-242379r960759_rule" severity="high">
    <result>fail</result>
  </rule-result>
</TestResult>
===COMPLIANCE_RESULT_END===
Some logs after`,
			wantCount: 2,
			wantErr:   false,
			checkResult: &compliancev1alpha1.UnifiedCheckResult{
				ID:            "V-242376",
				Status:        unified.StatusPass,
				ActualValue:   "pass",
				ExpectedValue: "pass",
			},
		},
		{
			name: "valid openscap output without markers",
			rawOutput: `<?xml version="1.0" encoding="UTF-8"?>
<TestResult xmlns="http://checklists.nist.gov/xccdf/1.2">
  <rule-result idref="xccdf_mil.disa.stig_rule_SV-242376r960759_rule" severity="medium">
    <result>pass</result>
  </rule-result>
</TestResult>`,
			wantCount: 1,
			wantErr:   false,
			checkResult: &compliancev1alpha1.UnifiedCheckResult{
				ID:            "V-242376",
				Status:        unified.StatusPass,
				ActualValue:   "pass",
				ExpectedValue: "pass",
			},
		},
		{
			name:      "invalid XML",
			rawOutput: `===COMPLIANCE_RESULT_START===invalid xml===COMPLIANCE_RESULT_END===`,
			wantCount: 0,
			wantErr:   true,
		},
		{
			name:      "empty output",
			rawOutput: "",
			wantCount: 0,
			wantErr:   true,
		},
		{
			name: "Benchmark root format (OpenSCAP full output)",
			rawOutput: `--- Starting Evaluation ---
Title   Some rule
Result  fail
===COMPLIANCE_RESULT_START===
<?xml version="1.0" encoding="UTF-8"?>
<Benchmark xmlns="http://checklists.nist.gov/xccdf/1.2" id="xccdf_mil.disa.stig_benchmark_Kubernetes_STIG">
  <status date="2025-11-20">accepted</status>
  <title>Kubernetes STIG</title>
  <TestResult id="xccdf_org.open-scap_testresult" start-time="2026-06-05T08:57:24+00:00" end-time="2026-06-05T08:57:25+00:00">
    <benchmark href="/scap-content/scap-rule.xml" id="xccdf_mil.disa.stig_benchmark_Kubernetes_STIG"/>
    <profile idref="xccdf_mil.disa.stig_profile_MAC-1_Classified"/>
    <target>master01</target>
    <rule-result idref="xccdf_mil.disa.stig_rule_SV-242376r960759_rule" severity="medium" version="CNTR-K8-000150">
      <result>fail</result>
    </rule-result>
    <rule-result idref="xccdf_mil.disa.stig_rule_SV-242381r1043176_rule" severity="high" version="CNTR-K8-000220">
      <result>pass</result>
    </rule-result>
    <rule-result idref="xccdf_mil.disa.stig_rule_SV-242393r1137639_rule" severity="medium" version="CNTR-K8-000400">
      <result>notapplicable</result>
    </rule-result>
    <score system="urn:xccdf:scoring:default" maximum="100.000000">71.186440</score>
  </TestResult>
</Benchmark>
===COMPLIANCE_RESULT_END===`,
			wantCount: 3,
			wantErr:   false,
			checkResult: &compliancev1alpha1.UnifiedCheckResult{
				ID:            "V-242376",
				Status:        unified.StatusFail,
				ActualValue:   "fail",
				ExpectedValue: "pass",
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			p := NewParser()
			results, err := p.Parse(tt.rawOutput)

			if (err != nil) != tt.wantErr {
				t.Errorf("Parser.Parse() error = %v, wantErr %v", err, tt.wantErr)
				return
			}

			if !tt.wantErr {
				if len(results) != tt.wantCount {
					t.Errorf("Parser.Parse() got %d results, want %d", len(results), tt.wantCount)
				}

				if tt.checkResult != nil && len(results) > 0 {
					got := results[0]
					if got.ID != tt.checkResult.ID {
						t.Errorf("Parser.Parse() ID = %s, want %s", got.ID, tt.checkResult.ID)
					}
					if got.Status != tt.checkResult.Status {
						t.Errorf("Parser.Parse() Status = %s, want %s", got.Status, tt.checkResult.Status)
					}
					if got.ActualValue != tt.checkResult.ActualValue {
						t.Errorf("Parser.Parse() ActualValue = %s, want %s", got.ActualValue, tt.checkResult.ActualValue)
					}
					if got.ExpectedValue != tt.checkResult.ExpectedValue {
						t.Errorf("Parser.Parse() ExpectedValue = %s, want %s", got.ExpectedValue, tt.checkResult.ExpectedValue)
					}
				}
			}
		})
	}
}

func TestExtractVulnID(t *testing.T) {
	tests := []struct {
		idref string
		want  string
	}{
		{"xccdf_mil.disa.stig_rule_SV-242376r960759_rule", "V-242376"},
		{"xccdf_mil.disa.stig_rule_SV-245544r960759_rule", "V-245544"},
		{"invalid-idref", ""},
	}

	for _, tt := range tests {
		t.Run(tt.idref, func(t *testing.T) {
			got := extractVulnID(tt.idref)
			if got != tt.want {
				t.Errorf("extractVulnID(%s) = %s, want %s", tt.idref, got, tt.want)
			}
		})
	}
}

func TestMapOpenSCAPStatus(t *testing.T) {
	tests := []struct {
		result string
		want   string
	}{
		{"pass", unified.StatusPass},
		{"fail", unified.StatusFail},
		{"error", unified.StatusError},
		{"unknown", unified.StatusWarn},
		{"notapplicable", unified.StatusNotApplicable},
		{"notchecked", unified.StatusNotChecked},
		{"informational", unified.StatusInfo},
		{"notselected", ""},
		{"UNKNOWN", unified.StatusWarn},
	}

	for _, tt := range tests {
		t.Run(tt.result, func(t *testing.T) {
			got := mapOpenSCAPStatus(tt.result)
			if got != tt.want {
				t.Errorf("mapOpenSCAPStatus(%s) = %s, want %s", tt.result, got, tt.want)
			}
		})
	}
}