package usecase

import (
	"context"
	"fmt"
	"strings"

	modelkit "github.com/chaitin/ModelKit/v2/usecase"
	"github.com/chaitin/panda-wiki/domain"
	"github.com/chaitin/panda-wiki/log"
	"github.com/cloudwego/eino/components/prompt"
	"github.com/cloudwego/eino/schema"
)

type CreationUsecase struct {
	llm      *LLMUsecase
	model    *ModelUsecase
	logger   *log.Logger
	modelkit *modelkit.ModelKit
}

func NewCreationUsecase(logger *log.Logger, llm *LLMUsecase, model *ModelUsecase) *CreationUsecase {
	modelkit := modelkit.NewModelKit(logger.Logger)
	return &CreationUsecase{
		llm:      llm,
		model:    model,
		logger:   logger.WithModule("usecase.creation"),
		modelkit: modelkit,
	}
}

func (u *CreationUsecase) TextCreation(ctx context.Context, req *domain.TextReq, onChunk func(ctx context.Context, dataType, chunk string) error) error {
	model, err := u.model.GetChatModel(ctx)
	if err != nil {
		u.logger.Error("get chat model failed", log.Error(err))
		return domain.ErrModelNotConfigured
	}

	modelkitModel, err := model.ToModelkitModel()
	if err != nil {
		return fmt.Errorf("failed to convert model to modelkit model: %w", err)
	}
	chatModel, err := u.modelkit.GetChatModel(ctx, modelkitModel)
	if err != nil {
		return fmt.Errorf("get chat model failed: %w", err)
	}

	messages := []*schema.Message{
		{
			Role: "system",
			Content: "你是一位专业的文本编辑。你的任务是对输入的文本进行润色和优化。\n\n" +
				"规则：\n" +
				"1. 保持输入文本的原始语言\n" +
				"2. 禁止将文本翻译成其他语言\n" +
				"3. 保持原文的语言风格和表达方式\n\n" +
				"优化方向：\n" +
				"1. 内容优化：\n" +
				"   - 提高文本的清晰度和可读性\n" +
				"   - 确保逻辑流畅和连贯性\n" +
				"   - 保持原文的核心信息和重点\n" +
				"2. 语言优化：\n" +
				"   - 改进语法和句子结构\n" +
				"   - 使语言更加简洁有力\n" +
				"   - 优化用词和表达方式\n\n" +
				"输出要求：\n" +
				"1. 只返回优化后的文本\n" +
				"2. 不要添加任何解释或额外评论\n" +
				"3. 不要改变文本的语言\n" +
				"4. 保持原文的段落结构",
		},
		{
			Role:    "user",
			Content: req.Text,
		},
	}
	usage := &schema.TokenUsage{}
	err = u.llm.ChatWithAgent(ctx, chatModel, messages, usage, onChunk)
	if err != nil {
		return fmt.Errorf("chat with llm failed: %w", err)
	}
	return nil
}

func (u *CreationUsecase) TabComplete(ctx context.Context, req *domain.CompleteReq) (string, error) {
	// For FIM (Fill in Middle) style completion, we need to handle prefix and suffix
	if req.Prefix != "" || req.Suffix != "" {
		model, err := u.model.GetModelByType(ctx, domain.ModelTypeChat)
		if err != nil {
			u.logger.Error("get chat model failed", log.Error(err))
			return "", domain.ErrModelNotConfigured
		}

		modelkitModel, err := model.ToModelkitModel()
		if err != nil {
			return "", fmt.Errorf("failed to convert model to modelkit model: %w", err)
		}
		chatModel, err := u.modelkit.GetChatModel(ctx, modelkitModel)
		if err != nil {
			return "", fmt.Errorf("get chat model failed: %w", err)
		}

		template := prompt.FromMessages(schema.GoTemplate,
			schema.SystemMessage(domain.NodeFIMSystemPrompt),
			schema.UserMessage(domain.NodeFIMFormatter),
		)

		messages, err := template.Format(ctx, map[string]any{
			"Prefix": req.Prefix,
			"Suffix": req.Suffix,
		})
		if err != nil {
			return "", fmt.Errorf("failed to format message: %w", err)
		}

		// For FIM-style completion, we collect the response in a string instead of streaming
		var result strings.Builder
		onChunk := func(ctx context.Context, dataType, chunk string) error {
			result.WriteString(chunk)
			return nil
		}

		usage := &schema.TokenUsage{}
		err = u.llm.ChatWithAgent(ctx, chatModel, messages, usage, onChunk)
		if err != nil {
			return "", fmt.Errorf("chat with llm failed: %w", err)
		}

		completion := result.String()
		return completion, nil
	}
	return "", nil
}
