package mapping

import (
	"context"

	semantic "github.com/pingcap-inc/nexuscrm-contract/pkg/runtime/listviewv1"
	runtimev1 "github.com/pingcap-inc/nexuscrm-contract/wire-go/gen/runtime/v1"
)

func ToWireReadPrivateListViewsRequest(ctx context.Context, request semantic.ReadRequest) (*runtimev1.ReadPrivateListViewsRequest, error) {
	if err := requirePlatformSemanticShape(semantic.CapabilityName); err != nil {
		return nil, err
	}
	if err := semantic.ValidateReadRequest(ctx, request); err != nil {
		return nil, err
	}
	selector, ok := toWirePrivateListViewReadSelector(request.Selector)
	if !ok {
		return nil, invalidPlatformWire()
	}
	return &runtimev1.ReadPrivateListViewsRequest{
		Selector: selector, ObjectId: request.ObjectID, ViewId: request.ViewID,
		MinCatalogRevision: request.MinCatalogRevision,
	}, nil
}

func FromWireReadPrivateListViewsRequest(ctx context.Context, request *runtimev1.ReadPrivateListViewsRequest) (semantic.ReadRequest, error) {
	if err := requirePlatformSemanticShape(semantic.CapabilityName); err != nil {
		return semantic.ReadRequest{}, err
	}
	if request == nil {
		return semantic.ReadRequest{}, invalidPlatformWire()
	}
	selector, ok := fromWirePrivateListViewReadSelector(request.GetSelector())
	if !ok {
		return semantic.ReadRequest{}, invalidPlatformWire()
	}
	result := semantic.ReadRequest{
		Selector: selector, ObjectID: request.GetObjectId(), ViewID: request.GetViewId(),
		MinCatalogRevision: request.MinCatalogRevision,
	}
	if err := semantic.ValidateReadRequest(ctx, result); err != nil {
		return semantic.ReadRequest{}, err
	}
	return result, nil
}

func ToWireReadPrivateListViewsResponse(request semantic.ReadRequest, response semantic.ReadResponse) (*runtimev1.ReadPrivateListViewsResponse, error) {
	if err := requirePlatformSemanticShape(semantic.CapabilityName); err != nil {
		return nil, err
	}
	if err := semantic.ValidateReadResponse(request, response); err != nil {
		return nil, err
	}
	result := &runtimev1.ReadPrivateListViewsResponse{
		Views:    make([]*runtimev1.PrivateListView, 0, len(response.Views)),
		Receipts: toWireReceipts(response.Receipts, platformCapability(semantic.CapabilityName)),
	}
	for _, view := range response.Views {
		wireView, err := toWirePrivateListView(view)
		if err != nil {
			return nil, err
		}
		result.Views = append(result.Views, wireView)
	}
	if response.View != nil {
		view, err := toWirePrivateListView(*response.View)
		if err != nil {
			return nil, err
		}
		result.View = view
	}
	return result, nil
}

func FromWireReadPrivateListViewsResponse(request semantic.ReadRequest, response *runtimev1.ReadPrivateListViewsResponse) (semantic.ReadResponse, error) {
	if err := requirePlatformSemanticShape(semantic.CapabilityName); err != nil {
		return semantic.ReadResponse{}, err
	}
	if response == nil || response.GetReceipts() == nil {
		return semantic.ReadResponse{}, incompatibleFailureFor(platformCapability(semantic.CapabilityName))
	}
	receipts, err := fromWireReceipts(response.GetReceipts(), platformCapability(semantic.CapabilityName))
	if err != nil {
		return semantic.ReadResponse{}, err
	}
	result := semantic.ReadResponse{Views: make([]semantic.View, 0, len(response.GetViews())), Receipts: receipts}
	for _, view := range response.GetViews() {
		semanticView, err := fromWirePrivateListView(view)
		if err != nil {
			return semantic.ReadResponse{}, err
		}
		result.Views = append(result.Views, semanticView)
	}
	if response.GetView() != nil {
		view, err := fromWirePrivateListView(response.GetView())
		if err != nil {
			return semantic.ReadResponse{}, err
		}
		result.View = &view
	}
	if err := semantic.ValidateReadResponse(request, result); err != nil {
		return semantic.ReadResponse{}, err
	}
	return result, nil
}

func ToWireMutatePrivateListViewRequest(ctx context.Context, request semantic.MutateRequest) (*runtimev1.MutatePrivateListViewRequest, error) {
	if err := requirePlatformSemanticShape(semantic.CapabilityName); err != nil {
		return nil, err
	}
	if err := semantic.ValidateMutateRequest(ctx, request); err != nil {
		return nil, err
	}
	operation, ok := toWirePrivateListViewMutationOperation(request.Operation)
	if !ok {
		return nil, invalidPlatformWire()
	}
	result := &runtimev1.MutatePrivateListViewRequest{
		Operation: operation, ObjectId: request.ObjectID,
		ViewId: request.ViewID, MinCatalogRevision: request.MinCatalogRevision,
	}
	if request.Patch != nil {
		result.Patch = toWirePrivateListViewPatch(*request.Patch)
	}
	return result, nil
}

func FromWireMutatePrivateListViewRequest(ctx context.Context, request *runtimev1.MutatePrivateListViewRequest) (semantic.MutateRequest, error) {
	if err := requirePlatformSemanticShape(semantic.CapabilityName); err != nil {
		return semantic.MutateRequest{}, err
	}
	if request == nil {
		return semantic.MutateRequest{}, invalidPlatformWire()
	}
	operation, ok := fromWirePrivateListViewMutationOperation(request.GetOperation())
	if !ok {
		return semantic.MutateRequest{}, invalidPlatformWire()
	}
	result := semantic.MutateRequest{
		Operation: operation, ObjectID: request.GetObjectId(),
		ViewID: request.GetViewId(), MinCatalogRevision: request.MinCatalogRevision,
	}
	if request.GetPatch() != nil {
		patch, err := fromWirePrivateListViewPatch(request.GetPatch())
		if err != nil {
			return semantic.MutateRequest{}, err
		}
		result.Patch = &patch
	}
	if err := semantic.ValidateMutateRequest(ctx, result); err != nil {
		return semantic.MutateRequest{}, err
	}
	return result, nil
}

func ToWireMutatePrivateListViewResponse(request semantic.MutateRequest, response semantic.MutateResponse) (*runtimev1.MutatePrivateListViewResponse, error) {
	if err := requirePlatformSemanticShape(semantic.CapabilityName); err != nil {
		return nil, err
	}
	if err := semantic.ValidateMutateResponse(request, response); err != nil {
		return nil, err
	}
	result := &runtimev1.MutatePrivateListViewResponse{
		Receipts: toWireReceipts(response.Receipts, platformCapability(semantic.CapabilityName)),
	}
	if response.View != nil {
		view, err := toWirePrivateListView(*response.View)
		if err != nil {
			return nil, err
		}
		result.View = view
	}
	return result, nil
}

func FromWireMutatePrivateListViewResponse(request semantic.MutateRequest, response *runtimev1.MutatePrivateListViewResponse) (semantic.MutateResponse, error) {
	if err := requirePlatformSemanticShape(semantic.CapabilityName); err != nil {
		return semantic.MutateResponse{}, err
	}
	if response == nil || response.GetReceipts() == nil {
		return semantic.MutateResponse{}, incompatibleFailureFor(platformCapability(semantic.CapabilityName))
	}
	receipts, err := fromWireReceipts(response.GetReceipts(), platformCapability(semantic.CapabilityName))
	if err != nil {
		return semantic.MutateResponse{}, err
	}
	result := semantic.MutateResponse{Receipts: receipts}
	if response.GetView() != nil {
		view, err := fromWirePrivateListView(response.GetView())
		if err != nil {
			return semantic.MutateResponse{}, err
		}
		result.View = &view
	}
	if err := semantic.ValidateMutateResponse(request, result); err != nil {
		return semantic.MutateResponse{}, err
	}
	return result, nil
}

func toWirePrivateListView(view semantic.View) (*runtimev1.PrivateListView, error) {
	direction, ok := toWirePrivateListViewSortDirection(view.SortDirection)
	if !ok {
		return nil, internalPlatformWire()
	}
	return &runtimev1.PrivateListView{
		ViewId: view.ViewID, ObjectId: view.ObjectID, Label: view.Label,
		FilterExpression: view.FilterExpression, FilterLogic: view.FilterLogic,
		FieldIds: append([]string(nil), view.FieldIDs...), SortFieldId: view.SortFieldID,
		SortDirection: direction, StableName: view.StableName,
	}, nil
}

func fromWirePrivateListView(view *runtimev1.PrivateListView) (semantic.View, error) {
	if view == nil {
		return semantic.View{}, internalPlatformWire()
	}
	direction, ok := fromWirePrivateListViewSortDirection(view.GetSortDirection())
	if !ok {
		return semantic.View{}, internalPlatformWire()
	}
	return semantic.View{
		ViewID: view.GetViewId(), ObjectID: view.GetObjectId(), Label: view.GetLabel(),
		FilterExpression: view.GetFilterExpression(), FilterLogic: view.GetFilterLogic(),
		FieldIDs: append([]string(nil), view.GetFieldIds()...), SortFieldID: view.GetSortFieldId(),
		SortDirection: direction, StableName: view.GetStableName(),
	}, nil
}

func toWirePrivateListViewPatch(patch semantic.Patch) *runtimev1.PrivateListViewPatch {
	result := &runtimev1.PrivateListViewPatch{
		Label: patch.Label, FilterExpression: patch.FilterExpression, FilterLogic: patch.FilterLogic,
		SortFieldId: patch.SortFieldID, StableName: patch.StableName,
	}
	if patch.Fields != nil {
		result.Fields = &runtimev1.PrivateListViewFieldSelection{FieldIds: append([]string{}, patch.Fields.FieldIDs...)}
	}
	if patch.SortDirection != nil {
		direction, _ := toWirePrivateListViewSortDirection(*patch.SortDirection)
		result.SortDirection = &direction
	}
	return result
}

func fromWirePrivateListViewPatch(patch *runtimev1.PrivateListViewPatch) (semantic.Patch, error) {
	if patch == nil {
		return semantic.Patch{}, invalidPlatformWire()
	}
	result := semantic.Patch{
		Label: patch.Label, FilterExpression: patch.FilterExpression, FilterLogic: patch.FilterLogic,
		SortFieldID: patch.SortFieldId, StableName: patch.StableName,
	}
	if patch.GetFields() != nil {
		result.Fields = &semantic.FieldSelection{FieldIDs: append([]string{}, patch.GetFields().GetFieldIds()...)}
	}
	if patch.SortDirection != nil {
		direction, ok := fromWirePrivateListViewSortDirection(patch.GetSortDirection())
		if !ok {
			return semantic.Patch{}, invalidPlatformWire()
		}
		result.SortDirection = &direction
	}
	return result, nil
}

func toWirePrivateListViewReadSelector(value semantic.ReadSelector) (runtimev1.PrivateListViewReadSelector, bool) {
	switch value {
	case semantic.ReadList:
		return runtimev1.PrivateListViewReadSelector_PRIVATE_LIST_VIEW_READ_SELECTOR_LIST, true
	case semantic.ReadDescribe:
		return runtimev1.PrivateListViewReadSelector_PRIVATE_LIST_VIEW_READ_SELECTOR_DESCRIBE, true
	default:
		return runtimev1.PrivateListViewReadSelector_PRIVATE_LIST_VIEW_READ_SELECTOR_UNSPECIFIED, false
	}
}

func fromWirePrivateListViewReadSelector(value runtimev1.PrivateListViewReadSelector) (semantic.ReadSelector, bool) {
	switch value {
	case runtimev1.PrivateListViewReadSelector_PRIVATE_LIST_VIEW_READ_SELECTOR_LIST:
		return semantic.ReadList, true
	case runtimev1.PrivateListViewReadSelector_PRIVATE_LIST_VIEW_READ_SELECTOR_DESCRIBE:
		return semantic.ReadDescribe, true
	default:
		return "", false
	}
}

func toWirePrivateListViewMutationOperation(value semantic.MutationOperation) (runtimev1.PrivateListViewMutationOperation, bool) {
	switch value {
	case semantic.MutationCreate:
		return runtimev1.PrivateListViewMutationOperation_PRIVATE_LIST_VIEW_MUTATION_OPERATION_CREATE, true
	case semantic.MutationUpdate:
		return runtimev1.PrivateListViewMutationOperation_PRIVATE_LIST_VIEW_MUTATION_OPERATION_UPDATE, true
	case semantic.MutationDelete:
		return runtimev1.PrivateListViewMutationOperation_PRIVATE_LIST_VIEW_MUTATION_OPERATION_DELETE, true
	default:
		return runtimev1.PrivateListViewMutationOperation_PRIVATE_LIST_VIEW_MUTATION_OPERATION_UNSPECIFIED, false
	}
}

func fromWirePrivateListViewMutationOperation(value runtimev1.PrivateListViewMutationOperation) (semantic.MutationOperation, bool) {
	switch value {
	case runtimev1.PrivateListViewMutationOperation_PRIVATE_LIST_VIEW_MUTATION_OPERATION_CREATE:
		return semantic.MutationCreate, true
	case runtimev1.PrivateListViewMutationOperation_PRIVATE_LIST_VIEW_MUTATION_OPERATION_UPDATE:
		return semantic.MutationUpdate, true
	case runtimev1.PrivateListViewMutationOperation_PRIVATE_LIST_VIEW_MUTATION_OPERATION_DELETE:
		return semantic.MutationDelete, true
	default:
		return "", false
	}
}

func toWirePrivateListViewSortDirection(value semantic.SortDirection) (runtimev1.PrivateListViewSortDirection, bool) {
	switch value {
	case "":
		return runtimev1.PrivateListViewSortDirection_PRIVATE_LIST_VIEW_SORT_DIRECTION_UNSPECIFIED, true
	case semantic.SortAscending:
		return runtimev1.PrivateListViewSortDirection_PRIVATE_LIST_VIEW_SORT_DIRECTION_ASCENDING, true
	case semantic.SortDescending:
		return runtimev1.PrivateListViewSortDirection_PRIVATE_LIST_VIEW_SORT_DIRECTION_DESCENDING, true
	default:
		return runtimev1.PrivateListViewSortDirection_PRIVATE_LIST_VIEW_SORT_DIRECTION_UNSPECIFIED, false
	}
}

func fromWirePrivateListViewSortDirection(value runtimev1.PrivateListViewSortDirection) (semantic.SortDirection, bool) {
	switch value {
	case runtimev1.PrivateListViewSortDirection_PRIVATE_LIST_VIEW_SORT_DIRECTION_UNSPECIFIED:
		return "", true
	case runtimev1.PrivateListViewSortDirection_PRIVATE_LIST_VIEW_SORT_DIRECTION_ASCENDING:
		return semantic.SortAscending, true
	case runtimev1.PrivateListViewSortDirection_PRIVATE_LIST_VIEW_SORT_DIRECTION_DESCENDING:
		return semantic.SortDescending, true
	default:
		return "", false
	}
}
