package dialectsfcrm

import (
	"context"
	"net/http"
	"testing"
	"time"

	"github.com/nexuscrm/shared/pkg/contract"
	"github.com/nexuscrm/shared/pkg/dialect"
	"github.com/nexuscrm/shared/pkg/models"
)

func TestAdminAuditLogNeutralHandlerProjectsRowsAndClampsLimit(t *testing.T) {
	oldValue := "old"
	newValue := "new"
	action := "UPDATE"
	trace := "trace-1"
	changedAt := time.Date(2026, 6, 11, 12, 34, 56, 789, time.UTC)
	audit := &fakeAuditLogContract{
		result: &contract.AuditLogQueryResult{
			Rows: []contract.AuditLogRow{{
				ID:             "audit-1",
				ObjectAPIName:  "Account",
				RecordID:       "001",
				FieldName:      "Name",
				OldValue:       &oldValue,
				NewValue:       &newValue,
				ChangedByID:    "005",
				ChangedAt:      changedAt,
				ChangedAtValid: true,
				Action:         &action,
				TraceID:        &trace,
			}},
			Limit:  500,
			Offset: 7,
			Object: "Account",
		},
	}

	resp, err := AdminAuditLogNeutralHandler(context.Background(), &dialect.Request{
		Query: map[string][]string{
			"object":   {"Account"},
			"recordId": {"001"},
			"limit":    {"900"},
			"offset":   {"7"},
		},
		User: &models.UserSession{ID: "005"},
	}, dialect.Deps{Contracts: contract.Deps{AuditLog: audit}})
	if err != nil {
		t.Fatalf("handler err = %v", err)
	}
	if resp.Status != http.StatusOK {
		t.Fatalf("status = %d body=%#v", resp.Status, resp.Body)
	}
	if audit.req.Limit != 500 || audit.req.Offset != 7 || audit.req.ObjectAPIName != "Account" || audit.req.RecordID != "001" {
		t.Fatalf("contract request = %+v", audit.req)
	}

	body, ok := resp.Body.(adminAuditLogResponse)
	if !ok {
		t.Fatalf("body = %T, want adminAuditLogResponse", resp.Body)
	}
	if body.Count != 1 || body.Limit != 500 || body.Offset != 7 || body.Object != "Account" {
		t.Fatalf("unexpected envelope: %+v", body)
	}
	row := body.Records[0]
	if row.ID != "audit-1" || row.ObjectAPIName != "Account" || row.RecordID != "001" || row.FieldName != "Name" {
		t.Fatalf("unexpected row identity: %+v", row)
	}
	if row.OldValue == nil || *row.OldValue != "old" || row.NewValue == nil || *row.NewValue != "new" {
		t.Fatalf("unexpected old/new values: %+v", row)
	}
	if row.ChangedAt != "2026-06-11T12:34:56.000000789Z" || row.Action != "UPDATE" || row.TraceID != "trace-1" {
		t.Fatalf("unexpected projected fields: %+v", row)
	}
}

func TestAdminAuditLogNeutralHandlerRequiresObjectAndRecordID(t *testing.T) {
	resp, err := AdminAuditLogNeutralHandler(context.Background(), &dialect.Request{}, dialect.Deps{Contracts: contract.Deps{AuditLog: &fakeAuditLogContract{}}})
	if err != nil {
		t.Fatalf("handler err = %v", err)
	}
	if resp.Status != http.StatusBadRequest {
		t.Fatalf("status = %d body=%#v", resp.Status, resp.Body)
	}
	body := resp.Body.(map[string]any)
	if body["error"] != "object and recordId are required" {
		t.Fatalf("body = %#v", body)
	}
}

func TestAdminAuditLogNeutralHandlerUnavailable(t *testing.T) {
	resp, err := AdminAuditLogNeutralHandler(context.Background(), &dialect.Request{
		Query: map[string][]string{"object": {"Account"}, "recordId": {"001"}},
	}, dialect.Deps{})
	if err != nil {
		t.Fatalf("handler err = %v", err)
	}
	if resp.Status != http.StatusServiceUnavailable {
		t.Fatalf("status = %d body=%#v", resp.Status, resp.Body)
	}
	body := resp.Body.(map[string]any)
	if body["error"] != "audit log backend not initialized" {
		t.Fatalf("body = %#v", body)
	}
}

type fakeAuditLogContract struct {
	req    contract.AuditLogQueryRequest
	user   *models.UserSession
	result *contract.AuditLogQueryResult
	err    error
}

func (f *fakeAuditLogContract) QueryAuditLog(_ context.Context, req contract.AuditLogQueryRequest, user *models.UserSession) (*contract.AuditLogQueryResult, error) {
	f.req = req
	f.user = user
	return f.result, f.err
}
