package integration

import (
	"encoding/json"
	"errors"

	integrationbiz "kra/internal/biz/integration"
	"kra/pkg/database/migration"

	"gorm.io/gorm"
)

func Migrations() []migration.Step {
	return []migration.Step{
		{ID: "202608200001_data_infrastructure", Migrate: func(db *gorm.DB) error {
			return migration.CreateMissingTables(db, &ConfigPO{})
		}},
		{ID: "202608210001_communication_integration_defaults", Migrate: ensureCommunicationIntegrationConfigs},
		{ID: "202608200004_payment_defaults", Migrate: ensurePaymentIntegrationConfigs},
	}
}

func ensureCommunicationIntegrationConfigs(db *gorm.DB) error {
	defaults := []struct{ kind, provider string }{
		{integrationbiz.IntegrationKindMQ, "emqx"},
		{integrationbiz.IntegrationKindMQ, "rabbitmq"},
		{integrationbiz.IntegrationKindWebSocket, "melody"},
	}
	for _, item := range defaults {
		var row ConfigPO
		err := db.Where("kind = ? AND provider = ?", item.kind, item.provider).First(&row).Error
		if gorm.ErrRecordNotFound == err {
			values, marshalErr := json.Marshal(integrationbiz.DefaultIntegrationConfig(item.kind, item.provider))
			if marshalErr != nil {
				return marshalErr
			}
			if err = db.Create(&ConfigPO{Kind: item.kind, Provider: item.provider, Enabled: false, Config: string(values)}).Error; err != nil {
				return err
			}
			continue
		}
		if err != nil {
			return err
		}
	}
	return nil
}

func ensurePaymentIntegrationConfigs(db *gorm.DB) error {
	for _, definition := range integrationbiz.IntegrationDefinitions(integrationbiz.IntegrationKindPayment) {
		provider := definition.Provider
		var row ConfigPO
		err := db.Where("kind = ? AND provider = ?", integrationbiz.IntegrationKindPayment, provider).First(&row).Error
		defaults := integrationbiz.DefaultIntegrationConfig(integrationbiz.IntegrationKindPayment, provider)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			encoded, marshalErr := json.Marshal(defaults)
			if marshalErr != nil {
				return marshalErr
			}
			if err := db.Create(&ConfigPO{Kind: integrationbiz.IntegrationKindPayment, Provider: provider, Config: string(encoded)}).Error; err != nil {
				return err
			}
			continue
		}
		if err != nil {
			return err
		}
		values := integrationObject(json.RawMessage(row.Config))
		changed := false
		for key, value := range defaults {
			if _, exists := values[key]; !exists {
				values[key] = value
				changed = true
			}
		}
		if changed {
			encoded, marshalErr := json.Marshal(values)
			if marshalErr != nil {
				return marshalErr
			}
			if err := db.Model(&row).Update("config", string(encoded)).Error; err != nil {
				return err
			}
		}
	}
	return nil
}
