package taskboard

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

	"github.com/tidbcloud/AgentTeam/internal/coredb"
	"github.com/tidbcloud/AgentTeam/internal/store/tasktimeline"
)

func listInReviewChildTaskIDs(ctx context.Context, queryer coredb.Queryer, parentTaskID string) ([]string, error) {
	rows, err := queryer.Query(ctx, `
SELECT id
FROM tasks
WHERE parent_task_ref = $1
  AND status = $2
ORDER BY task_number ASC, created_at ASC, id ASC
`, parentTaskID, StatusInReview)
	if err != nil {
		return nil, fmt.Errorf("load subtasks for review rollup: %w", err)
	}
	defer rows.Close()

	taskIDs := make([]string, 0)
	for rows.Next() {
		var taskID string
		if err := rows.Scan(&taskID); err != nil {
			return nil, fmt.Errorf("scan subtasks for review rollup: %w", err)
		}
		taskIDs = append(taskIDs, taskID)
	}
	if err := rows.Err(); err != nil {
		return nil, fmt.Errorf("iterate subtasks for review rollup: %w", err)
	}
	return taskIDs, nil
}

func appendStringPlaceholders(args []any, values []string) (string, []any) {
	placeholders := make([]string, 0, len(values))
	for _, value := range values {
		args = append(args, value)
		placeholders = append(placeholders, fmt.Sprintf("$%d", len(args)))
	}
	return strings.Join(placeholders, ", "), args
}

func appendTaskStatusChangedEvents(ctx context.Context, tx coredb.Tx, taskIDs []string, actorMemberID string, payload string, now time.Time) error {
	if len(taskIDs) == 0 {
		return nil
	}

	trimmedActorRef := strings.TrimSpace(actorMemberID)
	trimmedPayload := strings.TrimSpace(payload)
	intents := make([]tasktimeline.TypedActivityIntent, 0, len(taskIDs))
	for _, taskID := range taskIDs {
		intents = append(intents, taskTypedEventIntent(taskID, trimmedActorRef, taskEventStatusChanged, trimmedPayload, now))
	}
	return applyTaskTypedEventPlan(ctx, tx, intents...)
}

func (txs TxStore) rollUpChildReviewsForParentTask(ctx context.Context, tx coredb.Tx, workspaceID string, parentTaskID string, actorMemberID string, now time.Time) error {
	childTaskIDs, err := listInReviewChildTaskIDs(ctx, tx, parentTaskID)
	if err != nil {
		return err
	}
	if len(childTaskIDs) == 0 {
		return nil
	}

	reviewArgs := []any{taskReviewStatusSuperseded, actorMemberID, now, taskReviewStatusRequested}
	reviewPlaceholders, reviewArgs := appendStringPlaceholders(reviewArgs, childTaskIDs)
	if _, err := tx.Exec(ctx, `
UPDATE task_review_requests
SET status = $1,
    decided_by_ref = $2,
    decided_at = $3
WHERE status = $4
  AND task_id IN (`+reviewPlaceholders+`)
`, reviewArgs...); err != nil {
		return fmt.Errorf("supersede child task reviews: %w", err)
	}

	taskArgs := []any{StatusDone, actorMemberID, now}
	taskPlaceholders, taskArgs := appendStringPlaceholders(taskArgs, childTaskIDs)
	if _, err := tx.Exec(ctx, `
UPDATE tasks
SET status = $1,
    completed_by_member_id = $2,
    completed_by_ref = $2,
    completed_at = $3,
    last_activity_at = $3,
    updated_at = $3
WHERE id IN (`+taskPlaceholders+`)
`, taskArgs...); err != nil {
		return fmt.Errorf("complete child task after review rollup: %w", err)
	}
	if err := appendTaskStatusChangedEvents(ctx, tx, childTaskIDs, actorMemberID, string(StatusDone), now); err != nil {
		return err
	}
	return nil
}

func (store *Store) rollUpChildReviewsForParentTask(ctx context.Context, tx coredb.Tx, workspaceID string, parentTaskID string, actorMemberID string, now time.Time) error {
	return store.InTx(tx).rollUpChildReviewsForParentTask(ctx, tx, workspaceID, parentTaskID, actorMemberID, now)
}
