package agentnode

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"time"

	agentmodel "github.com/LoveLosita/smartflow/backend/agent/model"
	"github.com/cloudwego/eino/components/tool"
	toolutils "github.com/cloudwego/eino/components/tool/utils"
	"github.com/cloudwego/eino/schema"
)

const (
	ToolNameTaskQueryTasks = "query_tasks"
	ToolDescTaskQueryTasks = "按象限、关键词、截止时间筛选并排序任务，返回结构化任务列表"
)

var taskQueryTimeLayouts = []string{
	time.RFC3339,
	"2006-01-02 15:04:05",
	"2006-01-02 15:04",
	"2006-01-02",
}

// TaskQueryToolDeps 描述任务查询工具依赖的外部查询能力。
//
// 职责边界：
// 1. QueryTasks 负责读取真实任务数据。
// 2. 工具层只负责参数校验、归一化和结构化输出，不直接耦合 DAO。
type TaskQueryToolDeps struct {
	QueryTasks func(ctx context.Context, req TaskQueryRequest) ([]TaskQueryTaskRecord, error)
}

// Validate 负责校验任务查询工具依赖是否齐全。
func (d TaskQueryToolDeps) Validate() error {
	if d.QueryTasks == nil {
		return errors.New("task query tool deps: QueryTasks is nil")
	}
	return nil
}

// TaskQueryToolBundle 同时返回工具实例和工具元信息。
//
// 职责边界：
// 1. Tools 给执行节点使用。
// 2. ToolInfos 给模型注册 schema 使用。
type TaskQueryToolBundle struct {
	Tools     []tool.BaseTool
	ToolInfos []*schema.ToolInfo
}

// TaskQueryRequest 是工具层传给业务层的内部查询请求。
type TaskQueryRequest struct {
	UserID           int
	Quadrant         *int
	SortBy           string
	Order            string
	Limit            int
	IncludeCompleted bool
	Keyword          string
	DeadlineBefore   *time.Time
	DeadlineAfter    *time.Time
}

// TaskQueryTaskRecord 是业务层返回给工具层的任务记录。
type TaskQueryTaskRecord struct {
	ID                 int
	Title              string
	PriorityGroup      int
	IsCompleted        bool
	DeadlineAt         *time.Time
	UrgencyThresholdAt *time.Time
}

// TaskQueryToolInput 是暴露给大模型的工具入参。
type TaskQueryToolInput struct {
	Quadrant         *int   `json:"quadrant,omitempty" jsonschema:"description=可选象限(1~4)"`
	SortBy           string `json:"sort_by,omitempty" jsonschema:"description=排序字段(deadline|priority|id)"`
	Order            string `json:"order,omitempty" jsonschema:"description=排序方向(asc|desc)"`
	Limit            int    `json:"limit,omitempty" jsonschema:"description=返回条数，默认5，上限20"`
	IncludeCompleted *bool  `json:"include_completed,omitempty" jsonschema:"description=是否包含已完成任务，默认false"`
	Keyword          string `json:"keyword,omitempty" jsonschema:"description=可选标题关键词，模糊匹配"`
	DeadlineBefore   string `json:"deadline_before,omitempty" jsonschema:"description=可选截止时间上界，支持RFC3339或yyyy-MM-dd HH:mm"`
	DeadlineAfter    string `json:"deadline_after,omitempty" jsonschema:"description=可选截止时间下界，支持RFC3339或yyyy-MM-dd HH:mm"`
}

// TaskQueryToolOutput 是返回给模型的结构化结果。
type TaskQueryToolOutput struct {
	Total int                        `json:"total"`
	Items []agentmodel.TaskQueryItem `json:"items"`
}

// BuildTaskQueryToolBundle 负责构建任务查询工具包。
//
// 步骤说明：
// 1. 先校验依赖是否完整，避免生成一个运行时必定失败的工具。
// 2. 再把输入归一化成内部请求，调用业务查询函数拿到真实数据。
// 3. 最后把业务记录转换成统一的轻量任务视图，供模型和反思节点复用。
func BuildTaskQueryToolBundle(ctx context.Context, deps TaskQueryToolDeps) (*TaskQueryToolBundle, error) {
	if err := deps.Validate(); err != nil {
		return nil, err
	}

	queryTool, err := toolutils.InferTool(
		ToolNameTaskQueryTasks,
		ToolDescTaskQueryTasks,
		func(ctx context.Context, input *TaskQueryToolInput) (*TaskQueryToolOutput, error) {
			req, err := normalizeTaskQueryToolInput(input)
			if err != nil {
				return nil, err
			}

			records, err := deps.QueryTasks(ctx, req)
			if err != nil {
				return nil, err
			}

			items := make([]agentmodel.TaskQueryItem, 0, len(records))
			for _, record := range records {
				items = append(items, agentmodel.TaskQueryItem{
					ID:                 record.ID,
					Title:              record.Title,
					PriorityGroup:      record.PriorityGroup,
					PriorityLabel:      agentmodel.PriorityLabelCN(record.PriorityGroup),
					IsCompleted:        record.IsCompleted,
					DeadlineAt:         formatTaskQueryTime(record.DeadlineAt),
					UrgencyThresholdAt: formatTaskQueryTime(record.UrgencyThresholdAt),
				})
			}

			return &TaskQueryToolOutput{
				Total: len(items),
				Items: items,
			}, nil
		},
	)
	if err != nil {
		return nil, fmt.Errorf("构建任务查询工具失败: %w", err)
	}

	tools := []tool.BaseTool{queryTool}
	infos, err := collectToolInfos(ctx, tools)
	if err != nil {
		return nil, err
	}
	return &TaskQueryToolBundle{
		Tools:     tools,
		ToolInfos: infos,
	}, nil
}

// GetTaskQueryInvokableToolByName 按工具名提取可执行工具。
func GetTaskQueryInvokableToolByName(bundle *TaskQueryToolBundle, name string) (tool.InvokableTool, error) {
	if bundle == nil {
		return nil, errors.New("task query tool bundle is nil")
	}
	return getInvokableToolByName(bundle.Tools, bundle.ToolInfos, name)
}

// normalizeTaskQueryToolInput 负责参数默认值回填与合法性校验。
//
// 步骤说明：
// 1. 先准备默认值，保证空参数也能执行一次合理查询。
// 2. 再校验象限、排序、条数和时间区间，阻止非法参数下沉到业务层。
// 3. 若上下界冲突，则直接返回错误，避免查出必为空的结果。
func normalizeTaskQueryToolInput(input *TaskQueryToolInput) (TaskQueryRequest, error) {
	req := TaskQueryRequest{
		SortBy:           "deadline",
		Order:            "asc",
		Limit:            agentmodel.DefaultTaskQueryLimit,
		IncludeCompleted: false,
	}
	if input == nil {
		return req, nil
	}

	if input.Quadrant != nil {
		if *input.Quadrant < 1 || *input.Quadrant > 4 {
			return TaskQueryRequest{}, fmt.Errorf("quadrant=%d 非法，必须在 1~4", *input.Quadrant)
		}
		quadrant := *input.Quadrant
		req.Quadrant = &quadrant
	}

	if sortBy := strings.ToLower(strings.TrimSpace(input.SortBy)); sortBy != "" {
		req.SortBy = sortBy
	}
	switch req.SortBy {
	case "deadline", "priority", "id":
	default:
		return TaskQueryRequest{}, fmt.Errorf("sort_by=%s 非法，仅支持 deadline|priority|id", req.SortBy)
	}

	if order := strings.ToLower(strings.TrimSpace(input.Order)); order != "" {
		req.Order = order
	}
	switch req.Order {
	case "asc", "desc":
	default:
		return TaskQueryRequest{}, fmt.Errorf("order=%s 非法，仅支持 asc|desc", req.Order)
	}

	if input.Limit > 0 {
		req.Limit = input.Limit
	}
	if req.Limit > agentmodel.MaxTaskQueryLimit {
		req.Limit = agentmodel.MaxTaskQueryLimit
	}
	if req.Limit <= 0 {
		req.Limit = agentmodel.DefaultTaskQueryLimit
	}

	if input.IncludeCompleted != nil {
		req.IncludeCompleted = *input.IncludeCompleted
	}
	req.Keyword = strings.TrimSpace(input.Keyword)

	before, err := parseTaskQueryBoundaryTime(input.DeadlineBefore, true)
	if err != nil {
		return TaskQueryRequest{}, err
	}
	after, err := parseTaskQueryBoundaryTime(input.DeadlineAfter, false)
	if err != nil {
		return TaskQueryRequest{}, err
	}
	req.DeadlineBefore = before
	req.DeadlineAfter = after
	if req.DeadlineBefore != nil && req.DeadlineAfter != nil && req.DeadlineAfter.After(*req.DeadlineBefore) {
		return TaskQueryRequest{}, errors.New("deadline_after 不能晚于 deadline_before")
	}

	return req, nil
}

// parseTaskQueryBoundaryTime 解析截止时间上下界。
//
// 职责边界：
// 1. isUpper=true 时，纯日期补到当天 23:59:59。
// 2. isUpper=false 时，纯日期补到当天 00:00:00。
// 3. 不支持的格式直接返回错误，由调用方决定是否回退。
func parseTaskQueryBoundaryTime(raw string, isUpper bool) (*time.Time, error) {
	text := strings.TrimSpace(raw)
	if text == "" {
		return nil, nil
	}

	loc := time.Local
	for _, layout := range taskQueryTimeLayouts {
		var (
			parsed time.Time
			err    error
		)
		if layout == time.RFC3339 {
			parsed, err = time.Parse(layout, text)
			if err == nil {
				parsed = parsed.In(loc)
			}
		} else {
			parsed, err = time.ParseInLocation(layout, text, loc)
		}
		if err != nil {
			continue
		}

		if layout == "2006-01-02" {
			if isUpper {
				parsed = time.Date(parsed.Year(), parsed.Month(), parsed.Day(), 23, 59, 59, 0, loc)
			} else {
				parsed = time.Date(parsed.Year(), parsed.Month(), parsed.Day(), 0, 0, 0, 0, loc)
			}
		}
		return &parsed, nil
	}
	return nil, fmt.Errorf("时间格式不支持: %s", text)
}

// formatTaskQueryTime 负责把内部时间格式化为给模型展示的分钟级文本。
func formatTaskQueryTime(value *time.Time) string {
	if value == nil {
		return ""
	}
	return value.In(time.Local).Format("2006-01-02 15:04")
}
