package service

import (
	"context"
	"encoding/json"

	"kra/internal/biz"
	"kra/internal/service/dto"
)

type IntegrationConfigService struct{ uc *biz.IntegrationConfigUsecase }

func NewIntegrationConfigService(uc *biz.IntegrationConfigUsecase) *IntegrationConfigService {
	return &IntegrationConfigService{uc: uc}
}

func (s *IntegrationConfigService) List(ctx context.Context, kind string) ([]*dto.IntegrationConfigResponse, error) {
	configs, err := s.uc.List(ctx, kind)
	if err != nil {
		return nil, err
	}
	byProvider := make(map[string]*biz.IntegrationConfig, len(configs))
	for _, config := range configs {
		if config != nil {
			byProvider[config.Provider] = config
		}
	}
	definitions := biz.IntegrationDefinitions(kind)
	result := make([]*dto.IntegrationConfigResponse, 0, len(definitions)+len(configs))
	for _, definition := range definitions {
		config, configured := byProvider[definition.Provider]
		values := mergeConfigJSON(definition.Defaults, nil)
		enabled := false
		if configured {
			values = mergeConfigJSON(definition.Defaults, config.Values)
			enabled = config.Enabled
			delete(byProvider, definition.Provider)
		}
		result = append(result, &dto.IntegrationConfigResponse{Kind: definition.Kind, Provider: definition.Provider, Name: definition.Name, Description: definition.Description, Enabled: enabled, Configured: configured, Config: values, Fields: definition.Fields})
	}
	for _, config := range configs {
		if _, exists := byProvider[config.Provider]; !exists {
			continue
		}
		result = append(result, &dto.IntegrationConfigResponse{Kind: config.Kind, Provider: config.Provider, Name: config.Provider, Enabled: config.Enabled, Configured: true, Config: config.Values})
	}
	return result, nil
}

func (s *IntegrationConfigService) Find(ctx context.Context, kind, provider string) (*dto.IntegrationConfigResponse, error) {
	config, err := s.uc.Find(ctx, kind, provider)
	if err != nil {
		return nil, err
	}
	definition, found := biz.IntegrationDefinition(config.Kind, config.Provider)
	response := &dto.IntegrationConfigResponse{Kind: config.Kind, Provider: config.Provider, Name: config.Provider, Enabled: config.Enabled, Configured: true, Config: config.Values}
	if found {
		response.Name = definition.Name
		response.Description = definition.Description
		response.Fields = definition.Fields
		response.Config = mergeConfigJSON(definition.Defaults, config.Values)
	}
	return response, nil
}

func (s *IntegrationConfigService) Save(ctx context.Context, kind, provider string, req *dto.IntegrationConfigRequest) error {
	if req == nil {
		return s.uc.Save(ctx, nil)
	}
	return s.uc.Save(ctx, &biz.IntegrationConfig{Kind: kind, Provider: provider, Enabled: req.Enabled, Values: req.Config})
}

func (s *IntegrationConfigService) Delete(ctx context.Context, kind, provider string) error {
	return s.uc.Delete(ctx, kind, provider)
}

func mergeConfigJSON(defaults map[string]any, raw json.RawMessage) json.RawMessage {
	values := make(map[string]any, len(defaults))
	for key, value := range defaults {
		values[key] = value
	}
	stored := map[string]any{}
	_ = json.Unmarshal(raw, &stored)
	for key, value := range stored {
		values[key] = value
	}
	encoded, _ := json.Marshal(values)
	return encoded
}
