package repository

import (
	"context"
	"sync"

	domrepo "gateway/internal/model/member/domain/repository"
)

// MemoryTOTPProfileRepository keeps TOTP state in-process; placeholder until
// the P4 Mongo entity lands. The struct is safe for concurrent use.
type MemoryTOTPProfileRepository struct {
	mu      sync.Mutex
	records map[string]*domrepo.TOTPProfileRecord
}

// NewMemoryTOTPProfileRepository allocates an empty MemoryTOTPProfileRepository.
func NewMemoryTOTPProfileRepository() *MemoryTOTPProfileRepository {
	return &MemoryTOTPProfileRepository{records: make(map[string]*domrepo.TOTPProfileRecord)}
}

func (r *MemoryTOTPProfileRepository) Get(_ context.Context, tenantID, uid string) (*domrepo.TOTPProfileRecord, error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	rec, ok := r.records[totpProfileKey(tenantID, uid)]
	if !ok {
		return &domrepo.TOTPProfileRecord{}, nil
	}
	return cloneTOTPRecord(rec), nil
}

func (r *MemoryTOTPProfileRepository) Save(_ context.Context, tenantID, uid string, rec *domrepo.TOTPProfileRecord) error {
	r.mu.Lock()
	defer r.mu.Unlock()
	r.records[totpProfileKey(tenantID, uid)] = cloneTOTPRecord(rec)
	return nil
}

func (r *MemoryTOTPProfileRepository) Clear(_ context.Context, tenantID, uid string) error {
	r.mu.Lock()
	defer r.mu.Unlock()
	delete(r.records, totpProfileKey(tenantID, uid))
	return nil
}

func (r *MemoryTOTPProfileRepository) ConsumeBackupCode(_ context.Context, tenantID, uid, hash string) (bool, error) {
	r.mu.Lock()
	defer r.mu.Unlock()
	rec, ok := r.records[totpProfileKey(tenantID, uid)]
	if !ok {
		return false, nil
	}
	idx := -1
	for i, h := range rec.BackupCodesHash {
		if h == hash {
			idx = i
			break
		}
	}
	if idx < 0 {
		return false, nil
	}
	rec.BackupCodesHash = append(rec.BackupCodesHash[:idx], rec.BackupCodesHash[idx+1:]...)
	return true, nil
}

func (r *MemoryTOTPProfileRepository) ReplaceBackupCodes(_ context.Context, tenantID, uid string, hashes []string) error {
	r.mu.Lock()
	defer r.mu.Unlock()
	rec, ok := r.records[totpProfileKey(tenantID, uid)]
	if !ok {
		rec = &domrepo.TOTPProfileRecord{}
		r.records[totpProfileKey(tenantID, uid)] = rec
	}
	rec.BackupCodesHash = append([]string(nil), hashes...)
	return nil
}

func totpProfileKey(tenantID, uid string) string {
	return tenantID + ":" + uid
}

func cloneTOTPRecord(in *domrepo.TOTPProfileRecord) *domrepo.TOTPProfileRecord {
	if in == nil {
		return &domrepo.TOTPProfileRecord{}
	}
	out := *in
	if in.SecretCipher != nil {
		out.SecretCipher = append([]byte(nil), in.SecretCipher...)
	}
	if in.BackupCodesHash != nil {
		out.BackupCodesHash = append([]string(nil), in.BackupCodesHash...)
	}
	return &out
}

var _ domrepo.TOTPProfileRepository = (*MemoryTOTPProfileRepository)(nil)
