package usecase

import (
	"context"
	"strings"

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

	"github.com/google/uuid"
)

type useCase struct {
	repo domrepo.Repository
}

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

func (u *useCase) Create(ctx context.Context, req domusecase.CreateRequest) (*domusecase.FormulaSummary, error) {
	if err := requireActor(req.TenantID, req.OwnerUID, req.AccountID); err != nil {
		return nil, err
	}
	label := strings.TrimSpace(req.Label)
	if label == "" {
		label = "未命名公式"
	}
	sourceType := strings.TrimSpace(req.SourceType)
	if sourceType == "" {
		sourceType = entity.SourcePaste
	}
	formulaText := strings.TrimSpace(req.Formula)
	if formulaText == "" && strings.TrimSpace(req.PostTemplate) == "" {
		return nil, app.For(code.ThreadsAccount).InputMissingRequired("formula or post_template is required")
	}
	now := clock.NowUnixNano()
	item := &entity.ContentFormula{
		ID:              uuid.NewString(),
		TenantID:        req.TenantID,
		OwnerUID:        req.OwnerUID,
		AccountID:       req.AccountID,
		Label:           label,
		SourceType:      sourceType,
		SourceRef:       strings.TrimSpace(req.SourceRef),
		SourcePostText:  strings.TrimSpace(req.SourcePostText),
		SourceAuthor:    strings.TrimSpace(req.SourceAuthor),
		SourcePermalink: strings.TrimSpace(req.SourcePermalink),
		SourceMetrics:   req.SourceMetrics,
		Summary:         strings.TrimSpace(req.Summary),
		Wins:            req.Wins,
		Improvements:    req.Improvements,
		Formula:         formulaText,
		PostTemplate:    strings.TrimSpace(req.PostTemplate),
		HookPattern:     strings.TrimSpace(req.HookPattern),
		Structure:       strings.TrimSpace(req.Structure),
		ReplicationTips: req.ReplicationTips,
		Avoid:           req.Avoid,
		Tags:            req.Tags,
		CreateAt:        now,
		UpdateAt:        now,
	}
	if err := u.repo.Create(ctx, item); err != nil {
		return nil, err
	}
	summary := toSummary(*item)
	return &summary, nil
}

func (u *useCase) Get(ctx context.Context, tenantID, ownerUID, accountID, formulaID string) (*domusecase.FormulaSummary, error) {
	if err := requireActor(tenantID, ownerUID, accountID); err != nil {
		return nil, err
	}
	item, err := u.repo.Get(ctx, tenantID, ownerUID, accountID, formulaID)
	if err != nil {
		return nil, err
	}
	summary := toSummary(*item)
	return &summary, nil
}

func (u *useCase) Update(ctx context.Context, req domusecase.UpdateRequest) (*domusecase.FormulaSummary, error) {
	if err := requireActor(req.TenantID, req.OwnerUID, req.AccountID); err != nil {
		return nil, err
	}
	patch := map[string]interface{}{"update_at": clock.NowUnixNano()}
	if req.Label != nil {
		patch["label"] = strings.TrimSpace(*req.Label)
	}
	if req.Formula != nil {
		patch["formula"] = strings.TrimSpace(*req.Formula)
	}
	if req.PostTemplate != nil {
		patch["post_template"] = strings.TrimSpace(*req.PostTemplate)
	}
	if req.HookPattern != nil {
		patch["hook_pattern"] = strings.TrimSpace(*req.HookPattern)
	}
	if req.Structure != nil {
		patch["structure"] = strings.TrimSpace(*req.Structure)
	}
	if req.Tags != nil {
		patch["tags"] = req.Tags
	}
	if len(patch) == 1 {
		return nil, app.For(code.ThreadsAccount).InputMissingRequired("no fields to update")
	}
	item, err := u.repo.Update(ctx, req.TenantID, req.OwnerUID, req.AccountID, req.FormulaID, patch)
	if err != nil {
		return nil, err
	}
	summary := toSummary(*item)
	return &summary, nil
}

func (u *useCase) Delete(ctx context.Context, tenantID, ownerUID, accountID, formulaID string) error {
	if err := requireActor(tenantID, ownerUID, accountID); err != nil {
		return err
	}
	return u.repo.Delete(ctx, tenantID, ownerUID, accountID, formulaID)
}

func (u *useCase) List(ctx context.Context, req domusecase.ListRequest) (*domusecase.ListResult, error) {
	if err := requireActor(req.TenantID, req.OwnerUID, req.AccountID); err != nil {
		return nil, err
	}
	result, err := u.repo.List(ctx, domrepo.ListFilter{
		TenantID:   req.TenantID,
		OwnerUID:   req.OwnerUID,
		AccountID:  req.AccountID,
		SourceType: req.SourceType,
		Tag:        req.Tag,
		Page:       req.Page,
		PageSize:   req.PageSize,
	})
	if err != nil {
		return nil, err
	}
	out := make([]domusecase.FormulaSummary, 0, len(result.Items))
	for _, item := range result.Items {
		out = append(out, toSummary(item))
	}
	return &domusecase.ListResult{Items: out, Total: result.Total}, nil
}

func requireActor(tenantID, ownerUID, accountID string) error {
	if strings.TrimSpace(tenantID) == "" || strings.TrimSpace(ownerUID) == "" {
		return app.For(code.Auth).AuthUnauthorized("missing actor")
	}
	if strings.TrimSpace(accountID) == "" {
		return app.For(code.ThreadsAccount).InputMissingRequired("account_id is required")
	}
	return nil
}

func toSummary(item entity.ContentFormula) domusecase.FormulaSummary {
	return domusecase.FormulaSummary{
		ID:              item.ID,
		AccountID:       item.AccountID,
		Label:           item.Label,
		SourceType:      item.SourceType,
		SourceRef:       item.SourceRef,
		SourcePostText:  item.SourcePostText,
		SourceAuthor:    item.SourceAuthor,
		SourcePermalink: item.SourcePermalink,
		SourceMetrics:   item.SourceMetrics,
		Summary:         item.Summary,
		Wins:            item.Wins,
		Improvements:    item.Improvements,
		Formula:         item.Formula,
		PostTemplate:    item.PostTemplate,
		HookPattern:     item.HookPattern,
		Structure:       item.Structure,
		ReplicationTips: item.ReplicationTips,
		Avoid:           item.Avoid,
		Tags:            item.Tags,
		CreateAt:        item.CreateAt,
		UpdateAt:        item.UpdateAt,
	}
}
