package realname

import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"errors"
	"strings"
	"time"

	"hfb_sys/backend/pkg/crypto"
)

type Provider interface {
	Name() string
	Start(ctx context.Context, req StartRequest) (ProviderResult, error)
}

type StartRequest struct {
	UserID uint64
	Name   string
	IDNo   string
}

type ProviderResult struct {
	ProviderOrderNo string
	Status          string
	MaskedName      string
	EncryptedName   string // 加密的完整姓名
	MaskedIDNo      string
	EncryptedIDNo   string // 加密的完整身份证号
	VerifiedAt      *time.Time
	FailReason      string
}

type MockProvider struct {
	encryptor crypto.Encryptor
}

func NewMockProvider(encryptor crypto.Encryptor) *MockProvider {
	if encryptor == nil {
		encryptor = &crypto.MockEncryptor{}
	}
	return &MockProvider{encryptor: encryptor}
}

func (p *MockProvider) Name() string {
	return "mock"
}

func (p *MockProvider) Start(_ context.Context, req StartRequest) (ProviderResult, error) {
	if strings.TrimSpace(req.Name) == "" || strings.TrimSpace(req.IDNo) == "" {
		return ProviderResult{}, errors.New("name and id no are required")
	}
	orderNo, err := randomOrderNo()
	if err != nil {
		return ProviderResult{}, err
	}

	// 加密完整信息
	encryptedName, err := p.encryptor.Encrypt(req.Name)
	if err != nil {
		return ProviderResult{}, err
	}
	encryptedIDNo, err := p.encryptor.Encrypt(req.IDNo)
	if err != nil {
		return ProviderResult{}, err
	}

	now := time.Now()
	return ProviderResult{
		ProviderOrderNo: orderNo,
		Status:          StatusVerified,
		MaskedName:      maskName(req.Name),
		EncryptedName:   encryptedName,
		MaskedIDNo:      maskIDNo(req.IDNo),
		EncryptedIDNo:   encryptedIDNo,
		VerifiedAt:      &now,
	}, nil
}

func randomOrderNo() (string, error) {
	buf := make([]byte, 8)
	if _, err := rand.Read(buf); err != nil {
		return "", err
	}
	return "mock_rn_" + hex.EncodeToString(buf), nil
}

func maskName(name string) string {
	name = strings.TrimSpace(name)
	if len([]rune(name)) <= 1 {
		return name
	}
	runes := []rune(name)
	return string(runes[0]) + strings.Repeat("*", len(runes)-1)
}

func maskIDNo(idNo string) string {
	idNo = strings.TrimSpace(idNo)
	if len(idNo) <= 8 {
		return idNo
	}
	return idNo[:4] + strings.Repeat("*", len(idNo)-8) + idNo[len(idNo)-4:]
}
