package serverruntime

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"testing"

	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/models"
	apihostdialect "github.com/pingcap-inc/nexuscrm-api-host/dialect"
)

type testSystemPermissionCatalog struct {
	rows  []models.SystemPermission
	err   error
	calls int
}

func (c *testSystemPermissionCatalog) ListSystemPermissions(context.Context) ([]models.SystemPermission, error) {
	c.calls++
	if c.err != nil {
		return nil, c.err
	}
	return c.rows, nil
}

func hostPermission(permission constants.Permission) apihostdialect.Permission {
	return apihostdialect.Permission(permission)
}

func TestPermissionResolverFromSystemCatalogIsLazyAndActiveRowBacked(t *testing.T) {
	catalog := &testSystemPermissionCatalog{
		rows: []models.SystemPermission{
			{APIName: string(constants.PermViewSetup), IsActive: true},
			{APIName: string(constants.PermCustomizeApplication), IsActive: false},
			{APIName: string(constants.PermRunReports), IsActive: true},
			{APIName: "", IsActive: true},
		},
	}

	resolver := permissionResolverFromSystemCatalog(catalog)
	if catalog.calls != 0 {
		t.Fatalf("resolver eagerly loaded catalog; calls=%d, want 0", catalog.calls)
	}

	if !resolver(hostPermission(constants.PermViewSetup)) {
		t.Fatal("resolver did not recognize active ViewSetup permission")
	}
	if !resolver(hostPermission(constants.PermRunReports)) {
		t.Fatal("resolver did not recognize active RunReports permission")
	}
	if resolver(hostPermission(constants.PermCustomizeApplication)) {
		t.Fatal("resolver recognized inactive CustomizeApplication permission")
	}
	if resolver(hostPermission(constants.Permission("NotARealPermission"))) {
		t.Fatal("resolver recognized an unknown permission")
	}
	if catalog.calls != 1 {
		t.Fatalf("catalog calls=%d, want 1 (snapshot reused after first gate validation)", catalog.calls)
	}
}

func TestPermissionResolverFromSystemCatalogUsesExactPermissionKeys(t *testing.T) {
	catalog := &testSystemPermissionCatalog{
		rows: []models.SystemPermission{
			{APIName: string(constants.PermViewSetup), IsActive: true},
			{APIName: "  " + string(constants.PermRunReports) + "  ", IsActive: true},
		},
	}
	resolver := permissionResolverFromSystemCatalog(catalog)

	if resolver(hostPermission(constants.Permission(" " + string(constants.PermViewSetup) + " "))) {
		t.Fatal("resolver normalized a route-declared permission key")
	}
	if resolver(hostPermission(constants.PermRunReports)) {
		t.Fatal("resolver normalized a catalog permission APIName")
	}
	if catalog.calls != 1 {
		t.Fatalf("catalog calls=%d, want 1", catalog.calls)
	}
}

func TestPermissionResolverFromSystemCatalogRejectsEmptyWithoutLoading(t *testing.T) {
	catalog := &testSystemPermissionCatalog{
		rows: []models.SystemPermission{{APIName: string(constants.PermViewSetup), IsActive: true}},
	}
	resolver := permissionResolverFromSystemCatalog(catalog)

	if resolver(hostPermission(constants.Permission(""))) {
		t.Fatal("empty permission resolved true")
	}
	if catalog.calls != 0 {
		t.Fatalf("empty permission loaded catalog; calls=%d, want 0", catalog.calls)
	}
}

func TestPermissionResolverFromSystemCatalogPanicsOnLoadFailure(t *testing.T) {
	resolver := permissionResolverFromSystemCatalog(&testSystemPermissionCatalog{
		err: errors.New("catalog unavailable"),
	})

	defer func() {
		r := recover()
		if r == nil {
			t.Fatal("resolver did not panic on catalog load failure")
		}
		if got := fmt.Sprint(r); !strings.Contains(got, "failed to load system permission catalog") || !strings.Contains(got, "catalog unavailable") {
			t.Fatalf("panic = %q, want catalog load context", got)
		}
	}()
	_ = resolver(hostPermission(constants.PermViewSetup))
}

func TestPermissionResolverFromSystemCatalogPanicsOnMissingCatalog(t *testing.T) {
	resolver := permissionResolverFromSystemCatalog(nil)

	defer func() {
		r := recover()
		if r == nil {
			t.Fatal("resolver did not panic on missing catalog")
		}
		if got := fmt.Sprint(r); !strings.Contains(got, "system permission catalog is not configured") {
			t.Fatalf("panic = %q, want missing catalog context", got)
		}
	}()
	_ = resolver(hostPermission(constants.PermViewSetup))
}
