package catalogtenant

import (
	"context"
	"database/sql"

	tenantauthorityv1 "github.com/pingcap-inc/nexuscrm-contract/pkg/tenantlayoutbundleauthorityv1"
)

func persistNamespaceValue(
	ctx context.Context,
	tx *sql.Tx,
	command terminalCommand,
	request tenantauthorityv1.TenantNamespaceCommandRequest,
	desiredDigest string,
	current namespaceCurrent,
	present bool,
) error {
	var result sql.Result
	var err error
	switch request.Operation {
	case tenantauthorityv1.NamespaceOperationReserve:
		result, err = tx.ExecContext(ctx, `INSERT INTO _System_CatalogTenantNamespaceReservation
(TenantNamespaceId, ValueVersion, State, ValueDigest, LastCommandId,
CreatedDate, LastModifiedDate)
VALUES (?, ?, ?, ?, ?, CURRENT_TIMESTAMP(6), CURRENT_TIMESTAMP(6))`,
			request.DesiredNamespaceValue.TenantNamespaceID,
			request.DesiredNamespaceValue.ValueVersion,
			string(request.DesiredNamespaceValue.State),
			desiredDigest,
			string(command.CommandID),
		)
	case tenantauthorityv1.NamespaceOperationTombstone:
		if !present {
			return ErrConflict
		}
		result, err = tx.ExecContext(ctx, `UPDATE _System_CatalogTenantNamespaceReservation
SET ValueVersion = ?, State = ?, ValueDigest = ?, LastCommandId = ?,
LastModifiedDate = CURRENT_TIMESTAMP(6)
WHERE TenantNamespaceId = ? AND State = 'ACTIVE'
AND ValueDigest = ? AND LastCommandId = ?`,
			request.DesiredNamespaceValue.ValueVersion,
			string(request.DesiredNamespaceValue.State),
			desiredDigest,
			string(command.CommandID),
			request.TargetTenantNamespaceID,
			current.Digest,
			string(current.LastCommandID),
		)
	default:
		return ErrConflict
	}
	if isDuplicate(err) {
		return ErrConflict
	}
	if err != nil {
		return err
	}
	if err := requireOne(result); err != nil {
		return err
	}

	var prior any
	if present {
		prior = current.Digest
	}
	result, err = tx.ExecContext(ctx, `INSERT INTO _System_CatalogTenantNamespaceHistory
(CommandId, CommandSequence, TenantNamespaceId, ValueVersion, State,
ValueDigest, PriorValueDigest, CreatedDate)
VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP(6))`,
		string(command.CommandID),
		uintText(command.Sequence),
		request.DesiredNamespaceValue.TenantNamespaceID,
		request.DesiredNamespaceValue.ValueVersion,
		string(request.DesiredNamespaceValue.State),
		desiredDigest,
		prior,
	)
	if isDuplicate(err) {
		return ErrConflict
	}
	if err != nil {
		return err
	}
	return requireOne(result)
}

func persistBindingValue(
	ctx context.Context,
	tx *sql.Tx,
	command terminalCommand,
	request tenantauthorityv1.TenantOrgNamespaceBindingCommandRequest,
	desiredDigest string,
	current bindingCurrent,
	present bool,
) error {
	var result sql.Result
	var err error
	switch request.Operation {
	case tenantauthorityv1.BindingOperationBind:
		result, err = tx.ExecContext(ctx, `INSERT INTO _System_CatalogTenantOrgNamespaceBinding
(OrgId, TenantNamespaceId, ValueVersion, State, ValueDigest, LastCommandId,
CreatedDate, LastModifiedDate)
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP(6), CURRENT_TIMESTAMP(6))`,
			request.DesiredBindingValue.OrgID,
			request.DesiredBindingValue.TenantNamespaceID,
			request.DesiredBindingValue.ValueVersion,
			string(request.DesiredBindingValue.State),
			desiredDigest,
			string(command.CommandID),
		)
	case tenantauthorityv1.BindingOperationTombstone:
		if !present {
			return ErrConflict
		}
		result, err = tx.ExecContext(ctx, `UPDATE _System_CatalogTenantOrgNamespaceBinding
SET ValueVersion = ?, State = ?, ValueDigest = ?, LastCommandId = ?,
LastModifiedDate = CURRENT_TIMESTAMP(6)
WHERE OrgId = ? AND TenantNamespaceId = ? AND State = 'ACTIVE'
AND ValueDigest = ? AND LastCommandId = ?`,
			request.DesiredBindingValue.ValueVersion,
			string(request.DesiredBindingValue.State),
			desiredDigest,
			string(command.CommandID),
			request.TargetOrgID,
			current.Value.TenantNamespaceID,
			current.Digest,
			string(current.LastCommandID),
		)
	default:
		return ErrConflict
	}
	if isDuplicate(err) {
		return ErrConflict
	}
	if err != nil {
		return err
	}
	if err := requireOne(result); err != nil {
		return err
	}

	var prior any
	if present {
		prior = current.Digest
	}
	result, err = tx.ExecContext(ctx, `INSERT INTO _System_CatalogTenantOrgNamespaceBindingHistory
(CommandId, CommandSequence, OrgId, TenantNamespaceId, ValueVersion, State,
ValueDigest, PriorValueDigest, CreatedDate)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP(6))`,
		string(command.CommandID),
		uintText(command.Sequence),
		request.DesiredBindingValue.OrgID,
		request.DesiredBindingValue.TenantNamespaceID,
		request.DesiredBindingValue.ValueVersion,
		string(request.DesiredBindingValue.State),
		desiredDigest,
		prior,
	)
	if isDuplicate(err) {
		return ErrConflict
	}
	if err != nil {
		return err
	}
	return requireOne(result)
}

func persistSlotValue(
	ctx context.Context,
	tx *sql.Tx,
	command terminalCommand,
	request tenantauthorityv1.TenantLayoutBundleSlotCommandRequest,
	desiredDigest string,
	current slotCurrent,
	present bool,
) error {
	var result sql.Result
	var err error
	value := request.DesiredSlotValue
	switch request.Operation {
	case tenantauthorityv1.SlotOperationCreate:
		result, err = tx.ExecContext(ctx, `INSERT INTO _System_CatalogTenantLayoutBundleSlot
(TenantNamespaceId, LocalComponentKey, BundleKeyVersion, SlotOwnerKind,
ValueVersion, State, ValueDigest, LastCommandId, CreatedDate, LastModifiedDate)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP(6), CURRENT_TIMESTAMP(6))`,
			value.BundleKey.SlotOwnerNamespace,
			string(value.BundleKey.LocalComponentKey),
			value.BundleKey.BundleKeyVersion,
			string(value.BundleKey.SlotOwnerKind),
			value.ValueVersion,
			string(value.State),
			desiredDigest,
			string(command.CommandID),
		)
	case tenantauthorityv1.SlotOperationRetire:
		if !present {
			return ErrConflict
		}
		result, err = tx.ExecContext(ctx, `UPDATE _System_CatalogTenantLayoutBundleSlot
SET BundleKeyVersion = ?, SlotOwnerKind = ?, ValueVersion = ?, State = ?,
ValueDigest = ?, LastCommandId = ?, LastModifiedDate = CURRENT_TIMESTAMP(6)
WHERE TenantNamespaceId = ? AND LocalComponentKey = ? AND State = 'ACTIVE'
AND ValueDigest = ? AND LastCommandId = ?`,
			value.BundleKey.BundleKeyVersion,
			string(value.BundleKey.SlotOwnerKind),
			value.ValueVersion,
			string(value.State),
			desiredDigest,
			string(command.CommandID),
			value.BundleKey.SlotOwnerNamespace,
			string(value.BundleKey.LocalComponentKey),
			current.Digest,
			string(current.LastCommandID),
		)
	default:
		return ErrConflict
	}
	if isDuplicate(err) {
		return ErrConflict
	}
	if err != nil {
		return err
	}
	if err := requireOne(result); err != nil {
		return err
	}

	var prior any
	if present {
		prior = current.Digest
	}
	result, err = tx.ExecContext(ctx, `INSERT INTO _System_CatalogTenantLayoutBundleSlotHistory
(CommandId, CommandSequence, TenantNamespaceId, LocalComponentKey,
BundleKeyVersion, SlotOwnerKind, ValueVersion, State, ValueDigest,
PriorValueDigest, CreatedDate)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP(6))`,
		string(command.CommandID),
		uintText(command.Sequence),
		value.BundleKey.SlotOwnerNamespace,
		string(value.BundleKey.LocalComponentKey),
		value.BundleKey.BundleKeyVersion,
		string(value.BundleKey.SlotOwnerKind),
		value.ValueVersion,
		string(value.State),
		desiredDigest,
		prior,
	)
	if isDuplicate(err) {
		return ErrConflict
	}
	if err != nil {
		return err
	}
	return requireOne(result)
}
