package dialectsfcrm

import (
	"fmt"
	"strings"

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

const (
	connectorRecoveryLeadObject     = "Lead"
	connectorRecoveryContactObject  = "Contact"
	connectorRecoveryIDField        = "Id"
	connectorRecoveryDeletedField   = "IsDeleted"
	connectorRecoveryConvertedField = "IsConverted"
)

// ConnectorInboundRemoteIdentityRecoverySourceInput is the CRM lifecycle
// projection of a source row already locked by the L0 recovery transaction.
// It deliberately carries no connector owner, action identity, or snapshot.
type ConnectorInboundRemoteIdentityRecoverySourceInput struct {
	ObjectName    string
	RecordID      string
	Record        contract.Record
	RemoteIDField string
	RemoteID      string
}

// ConnectorInboundRemoteIdentityRecoveryMirrorState describes only the
// compatibility mirror readback. It is not remote-identity authority.
type ConnectorInboundRemoteIdentityRecoveryMirrorState string

const (
	ConnectorInboundRemoteIdentityRecoveryMirrorSynced  ConnectorInboundRemoteIdentityRecoveryMirrorState = "synced"
	ConnectorInboundRemoteIdentityRecoveryMirrorDrifted ConnectorInboundRemoteIdentityRecoveryMirrorState = "drifted"
)

// ValidateConnectorInboundRemoteIdentityRecoverySource applies the CRM-owned
// Lead and Contact lifecycle rules to a locked row. A blank mirror is allowed
// as drift, but this validator never writes it or chooses an identity owner.
func ValidateConnectorInboundRemoteIdentityRecoverySource(
	input ConnectorInboundRemoteIdentityRecoverySourceInput,
) (ConnectorInboundRemoteIdentityRecoveryMirrorState, error) {
	if input.ObjectName == "" || input.ObjectName != strings.TrimSpace(input.ObjectName) {
		return "", fmt.Errorf("connector recovery source object must be canonical and nonblank")
	}
	if input.RecordID == "" || input.RecordID != strings.TrimSpace(input.RecordID) {
		return "", fmt.Errorf("connector recovery source record ID must be canonical and nonblank")
	}
	if input.RemoteIDField == "" || input.RemoteIDField != strings.TrimSpace(input.RemoteIDField) {
		return "", fmt.Errorf("connector recovery remote ID field must be canonical and nonblank")
	}
	if input.RemoteID == "" || input.RemoteID != strings.TrimSpace(input.RemoteID) {
		return "", fmt.Errorf("connector recovery remote ID must be canonical and nonblank")
	}
	if input.Record == nil {
		return "", fmt.Errorf("connector recovery source record is required")
	}

	lockedID, ok := input.Record[connectorRecoveryIDField].(string)
	if !ok || lockedID != input.RecordID {
		return "", fmt.Errorf("connector recovery locked source record ID does not match the requested record")
	}
	deleted, err := connectorRecoveryRequiredBool(input.Record, connectorRecoveryDeletedField)
	if err != nil {
		return "", err
	}
	if deleted {
		return "", fmt.Errorf("connector recovery source record is deleted")
	}

	switch input.ObjectName {
	case connectorRecoveryLeadObject:
		converted, err := connectorRecoveryRequiredBool(input.Record, connectorRecoveryConvertedField)
		if err != nil {
			return "", err
		}
		if converted {
			return "", fmt.Errorf("connector recovery Lead is converted")
		}
	case connectorRecoveryContactObject:
		// Contact has no conversion lifecycle guard beyond the common tombstone.
	default:
		return "", fmt.Errorf("connector recovery source object %q is not supported by the CRM lifecycle validator", input.ObjectName)
	}

	mirror, exists := input.Record[input.RemoteIDField]
	if !exists {
		return ConnectorInboundRemoteIdentityRecoveryMirrorDrifted, nil
	}
	if mirror == nil {
		return ConnectorInboundRemoteIdentityRecoveryMirrorDrifted, nil
	}
	mirrorValue, ok := mirror.(string)
	if !ok {
		return "", fmt.Errorf("connector recovery compatibility mirror field %q must be a string or null", input.RemoteIDField)
	}
	if strings.TrimSpace(mirrorValue) == "" {
		return ConnectorInboundRemoteIdentityRecoveryMirrorDrifted, nil
	}
	if mirrorValue != input.RemoteID {
		return "", fmt.Errorf("connector recovery compatibility mirror field %q names a different remote ID", input.RemoteIDField)
	}
	return ConnectorInboundRemoteIdentityRecoveryMirrorSynced, nil
}

func connectorRecoveryRequiredBool(record contract.Record, field string) (bool, error) {
	value, exists := record[field]
	if !exists {
		return false, fmt.Errorf("connector recovery lifecycle field %q is missing from the locked source record", field)
	}
	boolean, ok := value.(bool)
	if !ok {
		return false, fmt.Errorf("connector recovery lifecycle field %q must be boolean", field)
	}
	return boolean, nil
}
