// Code scaffolded by goctl. Safe to edit.
// goctl 1.10.1

package brand

import (
	"context"
	"strings"

	app "haixun-backend/internal/library/errors"
	"haixun-backend/internal/library/errors/code"
	liboutreach "haixun-backend/internal/library/outreach"
	libplacement "haixun-backend/internal/library/placement"
	libthreads "haixun-backend/internal/library/threadsapi"
	"haixun-backend/internal/library/threadspost"
	scanpostentity "haixun-backend/internal/model/scan_post/domain/entity"
	scanpostusecase "haixun-backend/internal/model/scan_post/domain/usecase"
	"haixun-backend/internal/svc"
	"haixun-backend/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type PublishOutreachDraftLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewPublishOutreachDraftLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PublishOutreachDraftLogic {
	return &PublishOutreachDraftLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *PublishOutreachDraftLogic) PublishOutreachDraft(req *types.PublishOutreachDraftHandlerReq) (resp *types.PublishOutreachDraftData, err error) {
	tenantID, uid, err := actorFrom(l.ctx)
	if err != nil {
		return nil, err
	}
	scanPostID := strings.TrimSpace(req.ScanPostID)
	text := liboutreach.NormalizeDraftText(req.Text)
	confirm := req.Confirm
	if scanPostID == "" {
		return nil, app.For(code.Brand).InputMissingRequired("scan_post_id is required")
	}
	if !confirm {
		return nil, app.For(code.Brand).InputMissingRequired("請確認 confirm=true 後再發送留言")
	}
	if text == "" {
		return nil, app.For(code.Brand).InputMissingRequired("text is required")
	}
	if err := threadspost.ValidateReply(text); err != nil {
		return nil, app.For(code.Brand).InputInvalidFormat(err.Error())
	}

	if _, err := l.svcCtx.Brand.Get(l.ctx, tenantID, uid, req.ID); err != nil {
		return nil, err
	}
	post, err := l.svcCtx.ScanPost.Get(l.ctx, tenantID, uid, req.ID, scanPostID)
	if err != nil {
		return nil, err
	}
	rawTargetID := libplacement.ResolveReplyTargetID(post.ExternalID, post.Permalink)
	if rawTargetID == "" {
		return nil, app.For(code.Brand).InputMissingRequired("此貼文缺少 Threads 貼文 ID（external_id 或有效 permalink），無法透過 API 回覆")
	}

	cred, err := l.svcCtx.ThreadsAccount.ResolveMemberThreadsReplyCredential(l.ctx, tenantID, uid)
	if err != nil {
		return nil, err
	}
	storageState := ""
	if session, sessErr := l.svcCtx.ThreadsAccount.GetBrowserSession(l.ctx, tenantID, uid, cred.AccountID); sessErr == nil && session != nil {
		storageState = strings.TrimSpace(session.StorageState)
	}
	resolveInput := libplacement.ReplyMediaResolveInput{
		AccessToken:  cred.AccessToken,
		StorageState: storageState,
		ExternalID:   rawTargetID,
		Permalink:    post.Permalink,
		HintText:     post.Text,
	}
	replyToID, err := libplacement.ResolveReplyMediaForPublish(l.ctx, resolveInput)
	if err != nil {
		return nil, app.For(code.Brand).InputMissingRequired(err.Error())
	}
	apiClient := libthreads.NewClient(cred.AccessToken)
	if err := apiClient.PrimeReplyTargetForPublish(l.ctx, libthreads.ResolveReplyMediaInput{
		ExternalID: rawTargetID,
		Permalink:  post.Permalink,
		HintText:   post.Text,
	}, replyToID); err != nil {
		return nil, app.For(code.ThreadsAccount).SvcThirdParty("Threads API 無法回覆此貼文：" + err.Error())
	}
	result, err := libthreads.PublishReply(l.ctx, libthreads.PublishReplyInput{
		ThreadsUserID: cred.ThreadsUserID,
		AccessToken:   cred.AccessToken,
		ReplyToID:     replyToID,
		Text:          text,
	})
	if err != nil {
		return nil, app.For(code.ThreadsAccount).SvcThirdParty("Threads API 發送留言失敗：" + err.Error())
	}

	patch := scanpostusecase.UpdateOutreachRequest{
		TenantID:           tenantID,
		OwnerUID:           uid,
		BrandID:            req.ID,
		PostID:             scanPostID,
		Status:             scanpostentity.OutreachStatusPublished,
		PublishedReplyID:   result.MediaID,
		PublishedPermalink: result.Permalink,
	}
	if libthreads.IsNumericMediaID(replyToID) && !libthreads.IsNumericMediaID(post.ExternalID) {
		patch.ExternalID = replyToID
	}
	updated, err := l.svcCtx.ScanPost.UpdateOutreach(l.ctx, patch)
	if err != nil {
		return nil, err
	}

	return &types.PublishOutreachDraftData{
		ScanPostID:         scanPostID,
		ReplyID:            result.MediaID,
		Permalink:          result.Permalink,
		OutreachStatus:     updated.OutreachStatus,
		PublishedPermalink: updated.PublishedPermalink,
		Message:            "獲客留言已透過 Threads API 發送",
	}, nil
}
