//go:build crm

package serverruntime

import (
	"context"
	"database/sql"
	"fmt"
	"net/http"
	"strings"

	"github.com/gin-gonic/gin"
	"github.com/nexuscrm/kernel/pkg/ports"
	"github.com/nexuscrm/shared/pkg/constants"
	"github.com/nexuscrm/shared/pkg/dialect"
	sharederrors "github.com/nexuscrm/shared/pkg/errors"
	"github.com/nexuscrm/shared/pkg/models"
	"github.com/pingcap-inc/nexuscrm-controlplane/packs"
)

const crmDistributionPackName = "salesforce-crm-standard"

func testCRMProductHooks() ProductHooks {
	return ProductHooks{
		OwningAppPacks: []string{crmDistributionPackName},
		Capabilities: ProductCapabilities{
			RuntimeRouteSurfaces: []RuntimeRouteSurfaceRegistration{{
				Name: "test-salesforce-root-identity",
				Register: func(ctx RuntimeRouteSurfaceContext) error {
					handlers := append([]gin.HandlerFunc{}, ctx.DataAPIMiddleware...)
					handlers = append(handlers, func(c *gin.Context) {
						c.Status(http.StatusOK)
					})
					ctx.Router.GET("/id/:orgId/:userId", handlers...)
					return nil
				},
			}, {
				Name: "test-salesforce-related-list-candidates",
				Register: func(ctx RuntimeRouteSurfaceContext) error {
					handlers := append([]gin.HandlerFunc{}, ctx.DataAPIMiddleware...)
					handlers = append(handlers, func(c *gin.Context) {
						c.JSON(http.StatusOK, gin.H{"candidates": []any{}})
					})
					ctx.Router.GET("/ui-api/related-list-candidates/:objectApiName", handlers...)
					return nil
				},
			}},
		},
		Dialects: func(ctx DialectRegistrationContext) []dialect.Dialect {
			return []dialect.Dialect{testVersionedDataDialect{}}
		},
		ValidateComposition: func(_ context.Context, _ *sql.DB, activeAppPacks []ActiveAppPack) error {
			for _, row := range activeAppPacks {
				if strings.EqualFold(row.Name, crmDistributionPackName) {
					return nil
				}
			}
			if len(activeAppPacks) > 0 {
				return fmt.Errorf("but active app pack(s) are installed")
			}
			return nil
		},
	}
}

type testVersionedDataDialect struct{}

func (testVersionedDataDialect) Name() string       { return "test-versioned-data" }
func (testVersionedDataDialect) OwningPack() string { return crmDistributionPackName }
func (testVersionedDataDialect) BasePath() string   { return "/services/data" }
func (testVersionedDataDialect) Versions() []string {
	return []string{"v59.0", "v60.0", "v61.0", "v62.0", "v63.0"}
}
func (testVersionedDataDialect) ErrorProjector() dialect.Projector {
	return func(_ *dialect.Request, err *sharederrors.DomainWireError) (int, any, bool) {
		return http.StatusBadRequest, gin.H{"message": err.Message}, true
	}
}
func (testVersionedDataDialect) InternalErrorProjector() dialect.InternalErrorProjector {
	return func(req *dialect.Request) (int, any) {
		return http.StatusInternalServerError, gin.H{"version": req.Version}
	}
}
func (testVersionedDataDialect) Manifest() []dialect.Route {
	handler := func(context.Context, *dialect.Request, dialect.Deps) (*dialect.Response, error) {
		return &dialect.Response{Status: http.StatusOK, Body: gin.H{}}, nil
	}
	return []dialect.Route{
		{Method: http.MethodGet, Path: "/", Handler: handler},
		{Method: http.MethodGet, Path: "/id/:orgId/:userId", Handler: handler},
		{Method: http.MethodGet, Path: "/sobjects", Handler: handler},
		{Method: http.MethodGet, Path: "/sobjects/:sobject/describe", Handler: handler},
		{Method: http.MethodGet, Path: "/sobjects/:sobject/describe/layouts", Handler: handler},
		{Method: http.MethodGet, Path: "/sobjects/:sobject/describe/layouts/:recordTypeId", Handler: handler},
		{Method: http.MethodPost, Path: "/composite", Handler: handler},
		{Method: http.MethodPost, Path: "/composite/batch", Handler: handler},
		{Method: http.MethodPost, Path: "/composite/tree/:objectName", Handler: handler},
		{Method: http.MethodPost, Path: "/sobjects/:sobject", Handler: handler},
		{Method: http.MethodPatch, Path: "/sobjects/:sobject/:id", Handler: handler},
		{Method: http.MethodDelete, Path: "/sobjects/:sobject/:id", Handler: handler},
		{Method: http.MethodGet, Path: "/admin/connector/sync-status", Handler: handler},
	}
}

type routeSystemPermissionCatalogRepo struct {
	ports.PermissionRepository
}

func (*routeSystemPermissionCatalogRepo) ListSystemPermissions(context.Context) ([]models.SystemPermission, error) {
	return []models.SystemPermission{
		{APIName: string(constants.PermManageProfilesPermSets), IsActive: true},
		{APIName: string(constants.PermModifyMetadata), IsActive: true},
		{APIName: string(constants.PermCustomizeApplication), IsActive: true},
		{APIName: string(constants.PermModifyAllData), IsActive: true},
		{APIName: string(constants.PermViewFieldAuditTrail), IsActive: true},
		{APIName: string(constants.PermViewSetup), IsActive: true},
		{APIName: string(constants.PermManageNamedCredentials), IsActive: true},
		{APIName: string(constants.PermRunReports), IsActive: true},
		{APIName: string(constants.PermRunFlow), IsActive: true},
		{APIName: string(constants.PermManageReportsInPubFolders), IsActive: true},
		{APIName: string(constants.PermManageDashbdsInPubFolders), IsActive: true},
		{APIName: string(constants.PermManageUsers), IsActive: true},
	}, nil
}

func (*routeSystemPermissionCatalogRepo) GetAllRoles(context.Context) ([]*models.UserRole, error) {
	return nil, nil
}

func activeAppPacksFromCatalog(catalog map[string]bool) []packs.ActiveInstalledAppPack {
	var rows []packs.ActiveInstalledAppPack
	for name, active := range catalog {
		if active {
			rows = append(rows, packs.ActiveInstalledAppPack{
				Name:               name,
				SourceKind:         packs.PackSourceKindOfficialRepo,
				SourceURI:          name,
				SourceRevision:     activeAppPackTestSourceRevision(name),
				AppliedPayloadHash: "test-hash",
				DesiredPayloadHash: "test-hash",
			})
		}
	}
	return rows
}

func activeAppPackTestSourceRevision(name string) string {
	if strings.EqualFold(name, crmDistributionPackName) {
		return "test-crm-revision"
	}
	return "test-revision"
}
