package usecase

import (
	"context"
	"strings"

	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	"haixun-backend/internal/model/setting/domain/entity"
	domrepo "haixun-backend/internal/model/setting/domain/repository"
	domusecase "haixun-backend/internal/model/setting/domain/usecase"
)

type UseCase = domusecase.UseCase

type settingUseCase struct {
	repo domrepo.Repository
}

const (
	defaultLimit = int64(50)
	maxLimit     = int64(200)
)

func NewUseCase(repo domrepo.Repository) UseCase {
	return &settingUseCase{repo: repo}
}

func (u *settingUseCase) List(ctx context.Context, scope, scopeID string, page, pageSize int64) ([]*entity.Setting, int64, int64, int64, error) {
	if err := validateIdentity(scope, scopeID, "x"); err != nil {
		return nil, 0, 0, 0, err
	}
	if page <= 0 {
		page = 1
	}
	if pageSize <= 0 {
		pageSize = defaultLimit
	}
	if pageSize > maxLimit {
		pageSize = maxLimit
	}
	offset := (page - 1) * pageSize
	items, total, err := u.repo.List(ctx, scope, scopeID, offset, pageSize)
	return items, total, page, pageSize, err
}

func (u *settingUseCase) Get(ctx context.Context, scope, scopeID, key string) (*entity.Setting, error) {
	if err := validateIdentity(scope, scopeID, key); err != nil {
		return nil, err
	}

	return u.repo.Find(ctx, scope, scopeID, key)
}

func (u *settingUseCase) Upsert(ctx context.Context, req domusecase.UpsertRequest) (*entity.Setting, error) {
	if err := validateIdentity(req.Scope, req.ScopeID, req.Key); err != nil {
		return nil, err
	}
	if req.Value == nil {
		return nil, app.For(code.Setting).InputMissingRequired("setting value must not be empty")
	}
	return u.repo.Upsert(ctx, &entity.Setting{
		Scope:   req.Scope,
		ScopeID: req.ScopeID,
		Key:     req.Key,
		Value:   req.Value,
		Version: req.Version,
	})
}

func (u *settingUseCase) Delete(ctx context.Context, scope, scopeID, key string) error {
	if err := validateIdentity(scope, scopeID, key); err != nil {
		return err
	}
	return u.repo.Delete(ctx, scope, scopeID, key)
}

func validateIdentity(scope, scopeID, key string) error {
	switch scope {
	case "user", "account", "system":
	default:
		return app.For(code.Setting).InputInvalidFormat("invalid setting scope")
	}
	if strings.TrimSpace(scopeID) == "" || strings.TrimSpace(key) == "" {
		return app.For(code.Setting).InputMissingRequired("setting scope_id and key must not be empty")
	}
	return nil
}
