package persistence

import (
	"database/sql"
	"encoding/json"
	"fmt"
	"strings"

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

func (r *MetadataRepository) scanAction(row Scannable) (*models.ActionMetadata, error) {
	var action models.ActionMetadata
	var icon, targetObject, configJSON sql.NullString
	var ownerPack sql.NullString
	var createdDateVal, lastModifiedDateVal interface{}
	// NullBool, not bool: legacy warm-upgraded rows carry IsDeleted IS NULL
	// (treated as live by the COALESCE filters); a plain bool Scan would error
	// on them. The value is row-classification input only and is not projected.
	var isDeleted sql.NullBool

	// ColsSystemAction: ID, ObjectAPIName, Name, Label, Type, Icon, TargetObject, Config, OwnerPack, CreatedDate, LastModifiedDate, IsDeleted
	if err := row.Scan(&action.ID, &action.ObjectAPIName, &action.Name, &action.Label, &action.Type, &icon, &targetObject, &configJSON, &ownerPack, &createdDateVal, &lastModifiedDateVal, &isDeleted); err != nil {
		return nil, err
	}
	if icon.Valid {
		action.Icon = icon.String
	}
	if targetObject.Valid {
		action.TargetObject = &targetObject.String
	}
	if configJSON.Valid {
		r.unmarshalJSON(configJSON.String, &action.Config)
	}
	if ownerPack.Valid {
		action.OwnerPack = &ownerPack.String
	}
	return &action, nil
}

func (r *MetadataRepository) scanValidationRule(row Scannable) (*models.ValidationRule, error) {
	var rule models.ValidationRule
	var active int
	var description, errorDisplayField, recordSetBindings, ownerPack sql.NullString
	var createdDateVal, lastModifiedDateVal interface{}
	// ColsSystemValidationRule includes RecordSetBindings before IsCustomized
	// and OwnerPack before timestamps.
	if err := row.Scan(&rule.ID, &rule.ObjectAPIName, &rule.Name, &description, &active, &rule.Condition, &rule.ErrorMessage, &errorDisplayField, &recordSetBindings, &rule.IsCustomized, &ownerPack, &createdDateVal, &lastModifiedDateVal); err != nil {
		return nil, err
	}
	rule.Active = active != 0
	if description.Valid {
		rule.Description = &description.String
	}
	if errorDisplayField.Valid {
		rule.ErrorDisplayField = &errorDisplayField.String
	}
	if recordSetBindings.Valid && strings.TrimSpace(recordSetBindings.String) != "" {
		bindings, err := decodeValidationRuleRecordSetBindings(recordSetBindings.String)
		if err != nil {
			return nil, err
		}
		rule.RecordSetBindings = bindings
	}
	if ownerPack.Valid {
		rule.OwnerPack = &ownerPack.String
	}
	return &rule, nil
}

func decodeValidationRuleRecordSetBindings(data string) ([]models.ValidationRuleRecordSetBinding, error) {
	if !json.Valid([]byte(data)) {
		return nil, fmt.Errorf("decode validation rule recordSetBindings: invalid JSON")
	}
	decoder := json.NewDecoder(strings.NewReader(data))
	decoder.UseNumber()
	var bindings []models.ValidationRuleRecordSetBinding
	if err := decoder.Decode(&bindings); err != nil {
		return nil, fmt.Errorf("decode validation rule recordSetBindings: %w", err)
	}
	return bindings, nil
}
