package cron

import (
	"context"
	"fmt"
	"os"
	"strings"

	"github.com/enmanuel/agents/internal/config"
	coretypes "github.com/enmanuel/agents/pkg/llm"
)

const actionKindSendMessage = "send_message"
const actionKindLLMPrompt = "llm_prompt"

// handler is a function that fires when a schedule triggers.
type handler func(ctx context.Context, room string)

// buildHandler returns the handler for a schedule, or nil for unsupported kinds.
func (s *Scheduler) buildHandler(sc config.ScheduleCfg) handler {
	switch sc.Action.Kind {
	case actionKindSendMessage:
		return s.sendMessageHandler(sc)
	case actionKindLLMPrompt:
		return s.llmPromptHandler(sc)
	default:
		return nil
	}
}

// sendMessageHandler returns a handler that sends a static message to a Matrix room.
// The message content is resolved in priority order: Message > Template file.
func (s *Scheduler) sendMessageHandler(sc config.ScheduleCfg) handler {
	return func(ctx context.Context, room string) {
		content, err := resolveContent(sc.Action.Message, sc.Action.Template)
		if err != nil {
			s.logger.Error("send_message: failed to resolve content",
				"name", sc.Name, "err", err)
			return
		}
		if content == "" {
			s.logger.Warn("send_message: empty content, skipping", "name", sc.Name)
			return
		}

		s.logger.Info("cron_fire", "name", sc.Name, "kind", actionKindSendMessage, "room", room)
		if err := s.sender.SendMarkdown(ctx, room, content); err != nil {
			s.logger.Error("send_message: bus send failed",
				"name", sc.Name, "room", room, "err", err)
		}
	}
}

// llmPromptHandler returns a handler that calls the LLM with a prompt and sends
// the response to a Matrix room.
func (s *Scheduler) llmPromptHandler(sc config.ScheduleCfg) handler {
	return func(ctx context.Context, room string) {
		if s.llm == nil {
			s.logger.Warn("llm_prompt: no LLM configured, skipping", "name", sc.Name)
			return
		}

		prompt, err := resolveContent(sc.Action.Prompt, sc.Action.Template)
		if err != nil {
			s.logger.Error("llm_prompt: failed to resolve prompt",
				"name", sc.Name, "err", err)
			return
		}
		if prompt == "" {
			s.logger.Warn("llm_prompt: empty prompt, skipping", "name", sc.Name)
			return
		}

		s.logger.Info("cron_fire", "name", sc.Name, "kind", actionKindLLMPrompt, "room", room)

		req := coretypes.CompletionRequest{
			Model: s.model,
			Messages: []coretypes.Message{
				{Role: coretypes.RoleUser, Content: prompt},
			},
		}

		resp, err := s.llm(ctx, req)
		if err != nil {
			s.logger.Error("llm_prompt: LLM call failed",
				"name", sc.Name, "err", err)
			return
		}

		content := strings.TrimSpace(resp.Content)
		if content == "" {
			s.logger.Warn("llm_prompt: LLM returned empty response", "name", sc.Name)
			return
		}

		if err := s.sender.SendMarkdown(ctx, room, content); err != nil {
			s.logger.Error("llm_prompt: bus send failed",
				"name", sc.Name, "room", room, "err", err)
		}
	}
}

// resolveContent returns the inline text if non-empty, otherwise reads the file at templatePath.
func resolveContent(inline, templatePath string) (string, error) {
	if inline != "" {
		return inline, nil
	}
	if templatePath == "" {
		return "", nil
	}
	data, err := os.ReadFile(templatePath)
	if err != nil {
		return "", fmt.Errorf("reading template %q: %w", templatePath, err)
	}
	return strings.TrimSpace(string(data)), nil
}
