package service

import (
	"baron-sso-backend/internal/domain"
	"context"
	"encoding/json"
	"fmt"
	"strings"
	"time"
)

type IdentityUpdateRequest struct {
	IdentityID string
	Traits     map[string]any
	State      string
	Reason     string
	Source     string
}

type IdentityWriteService interface {
	GetIdentity(ctx context.Context, identityID string) (*KratosIdentity, error)
	UpdateIdentity(ctx context.Context, req IdentityUpdateRequest) (*KratosIdentity, error)
}

type identityWriteService struct {
	kratos KratosAdminService
	redis  domain.RedisRepository
}

func NewIdentityWriteService(kratos KratosAdminService, redis domain.RedisRepository) IdentityWriteService {
	return &identityWriteService{
		kratos: kratos,
		redis:  redis,
	}
}

func (s *identityWriteService) GetIdentity(ctx context.Context, identityID string) (*KratosIdentity, error) {
	if s == nil || s.kratos == nil {
		return nil, fmt.Errorf("kratos admin service is required")
	}
	return s.kratos.GetIdentity(ctx, identityID)
}

func (s *identityWriteService) UpdateIdentity(ctx context.Context, req IdentityUpdateRequest) (*KratosIdentity, error) {
	if s == nil || s.kratos == nil {
		return nil, fmt.Errorf("kratos admin service is required")
	}
	updated, err := s.kratos.UpdateIdentity(ctx, req.IdentityID, req.Traits, req.State)
	if err != nil {
		return nil, err
	}
	_ = s.markIdentityMirrorStale(req)
	return updated, nil
}

func (s *identityWriteService) markIdentityMirrorStale(req IdentityUpdateRequest) error {
	if s == nil || s.redis == nil {
		return nil
	}
	now := time.Now().UTC()
	reason := strings.TrimSpace(req.Reason)
	if reason == "" {
		reason = "identity_write"
	}
	source := strings.TrimSpace(req.Source)
	if source != "" {
		reason = source + ": " + reason
	}
	state := domain.IdentityCacheStatus{
		Status:    "stale",
		LastError: reason,
		UpdatedAt: &now,
	}
	raw, err := json.Marshal(state)
	if err != nil {
		return err
	}
	return s.redis.Set("identity:mirror:state", string(raw), 0)
}
