// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.27.0
// source: toolcalls.sql

package database

import (
	"context"
	"database/sql"
	"encoding/json"
	"time"
)

const createToolcall = `-- name: CreateToolcall :one
INSERT INTO toolcalls (
  call_id,
  status,
  name,
  args,
  flow_id,
  task_id,
  subtask_id
) VALUES (
  $1, $2, $3, $4, $5, $6, $7
)
RETURNING id, call_id, status, name, args, result, flow_id, task_id, subtask_id, created_at, updated_at, duration_seconds
`

type CreateToolcallParams struct {
	CallID    string          `json:"call_id"`
	Status    ToolcallStatus  `json:"status"`
	Name      string          `json:"name"`
	Args      json.RawMessage `json:"args"`
	FlowID    int64           `json:"flow_id"`
	TaskID    sql.NullInt64   `json:"task_id"`
	SubtaskID sql.NullInt64   `json:"subtask_id"`
}

func (q *Queries) CreateToolcall(ctx context.Context, arg CreateToolcallParams) (Toolcall, error) {
	row := q.db.QueryRowContext(ctx, createToolcall,
		arg.CallID,
		arg.Status,
		arg.Name,
		arg.Args,
		arg.FlowID,
		arg.TaskID,
		arg.SubtaskID,
	)
	var i Toolcall
	err := row.Scan(
		&i.ID,
		&i.CallID,
		&i.Status,
		&i.Name,
		&i.Args,
		&i.Result,
		&i.FlowID,
		&i.TaskID,
		&i.SubtaskID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DurationSeconds,
	)
	return i, err
}

const getAllFlowsToolcallsStats = `-- name: GetAllFlowsToolcallsStats :many
SELECT
  tc.flow_id AS flow_id,
  COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
  COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON f.id = tc.flow_id
WHERE f.deleted_at IS NULL
GROUP BY tc.flow_id
ORDER BY tc.flow_id
`

type GetAllFlowsToolcallsStatsRow struct {
	FlowID               int64   `json:"flow_id"`
	TotalCount           int64   `json:"total_count"`
	TotalDurationSeconds float64 `json:"total_duration_seconds"`
}

// Get toolcalls stats for all flows
func (q *Queries) GetAllFlowsToolcallsStats(ctx context.Context) ([]GetAllFlowsToolcallsStatsRow, error) {
	rows, err := q.db.QueryContext(ctx, getAllFlowsToolcallsStats)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetAllFlowsToolcallsStatsRow
	for rows.Next() {
		var i GetAllFlowsToolcallsStatsRow
		if err := rows.Scan(&i.FlowID, &i.TotalCount, &i.TotalDurationSeconds); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getCallToolcall = `-- name: GetCallToolcall :one
SELECT
  tc.id, tc.call_id, tc.status, tc.name, tc.args, tc.result, tc.flow_id, tc.task_id, tc.subtask_id, tc.created_at, tc.updated_at, tc.duration_seconds
FROM toolcalls tc
WHERE tc.call_id = $1
`

func (q *Queries) GetCallToolcall(ctx context.Context, callID string) (Toolcall, error) {
	row := q.db.QueryRowContext(ctx, getCallToolcall, callID)
	var i Toolcall
	err := row.Scan(
		&i.ID,
		&i.CallID,
		&i.Status,
		&i.Name,
		&i.Args,
		&i.Result,
		&i.FlowID,
		&i.TaskID,
		&i.SubtaskID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DurationSeconds,
	)
	return i, err
}

const getFlowToolcall = `-- name: GetFlowToolcall :one
SELECT
  tc.id, tc.call_id, tc.status, tc.name, tc.args, tc.result, tc.flow_id, tc.task_id, tc.subtask_id, tc.created_at, tc.updated_at, tc.duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON tc.flow_id = f.id
WHERE tc.id = $1 AND tc.flow_id = $2 AND f.deleted_at IS NULL
`

type GetFlowToolcallParams struct {
	ID     int64 `json:"id"`
	FlowID int64 `json:"flow_id"`
}

func (q *Queries) GetFlowToolcall(ctx context.Context, arg GetFlowToolcallParams) (Toolcall, error) {
	row := q.db.QueryRowContext(ctx, getFlowToolcall, arg.ID, arg.FlowID)
	var i Toolcall
	err := row.Scan(
		&i.ID,
		&i.CallID,
		&i.Status,
		&i.Name,
		&i.Args,
		&i.Result,
		&i.FlowID,
		&i.TaskID,
		&i.SubtaskID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DurationSeconds,
	)
	return i, err
}

const getFlowToolcalls = `-- name: GetFlowToolcalls :many
SELECT
  tc.id, tc.call_id, tc.status, tc.name, tc.args, tc.result, tc.flow_id, tc.task_id, tc.subtask_id, tc.created_at, tc.updated_at, tc.duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON tc.flow_id = f.id
WHERE tc.flow_id = $1 AND f.deleted_at IS NULL
ORDER BY tc.created_at ASC
`

func (q *Queries) GetFlowToolcalls(ctx context.Context, flowID int64) ([]Toolcall, error) {
	rows, err := q.db.QueryContext(ctx, getFlowToolcalls, flowID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []Toolcall
	for rows.Next() {
		var i Toolcall
		if err := rows.Scan(
			&i.ID,
			&i.CallID,
			&i.Status,
			&i.Name,
			&i.Args,
			&i.Result,
			&i.FlowID,
			&i.TaskID,
			&i.SubtaskID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DurationSeconds,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getFlowToolcallsStats = `-- name: GetFlowToolcallsStats :one

SELECT
  COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
  COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON f.id = tc.flow_id
WHERE tc.flow_id = $1 AND f.deleted_at IS NULL
`

type GetFlowToolcallsStatsRow struct {
	TotalCount           int64   `json:"total_count"`
	TotalDurationSeconds float64 `json:"total_duration_seconds"`
}

// ==================== Toolcalls Analytics Queries ====================
// Get total execution time and count of toolcalls for a specific flow
func (q *Queries) GetFlowToolcallsStats(ctx context.Context, flowID int64) (GetFlowToolcallsStatsRow, error) {
	row := q.db.QueryRowContext(ctx, getFlowToolcallsStats, flowID)
	var i GetFlowToolcallsStatsRow
	err := row.Scan(&i.TotalCount, &i.TotalDurationSeconds)
	return i, err
}

const getSubtaskToolcalls = `-- name: GetSubtaskToolcalls :many
SELECT
  tc.id, tc.call_id, tc.status, tc.name, tc.args, tc.result, tc.flow_id, tc.task_id, tc.subtask_id, tc.created_at, tc.updated_at, tc.duration_seconds
FROM toolcalls tc
INNER JOIN subtasks s ON tc.subtask_id = s.id
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE tc.subtask_id = $1 AND f.deleted_at IS NULL
ORDER BY tc.created_at DESC
`

func (q *Queries) GetSubtaskToolcalls(ctx context.Context, subtaskID sql.NullInt64) ([]Toolcall, error) {
	rows, err := q.db.QueryContext(ctx, getSubtaskToolcalls, subtaskID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []Toolcall
	for rows.Next() {
		var i Toolcall
		if err := rows.Scan(
			&i.ID,
			&i.CallID,
			&i.Status,
			&i.Name,
			&i.Args,
			&i.Result,
			&i.FlowID,
			&i.TaskID,
			&i.SubtaskID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DurationSeconds,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getSubtaskToolcallsStats = `-- name: GetSubtaskToolcallsStats :one
SELECT
  COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
  COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
INNER JOIN subtasks s ON tc.subtask_id = s.id
INNER JOIN tasks t ON s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE tc.subtask_id = $1 AND f.deleted_at IS NULL AND s.id IS NOT NULL AND t.id IS NOT NULL
`

type GetSubtaskToolcallsStatsRow struct {
	TotalCount           int64   `json:"total_count"`
	TotalDurationSeconds float64 `json:"total_duration_seconds"`
}

// Get total execution time and count of toolcalls for a specific subtask
func (q *Queries) GetSubtaskToolcallsStats(ctx context.Context, subtaskID sql.NullInt64) (GetSubtaskToolcallsStatsRow, error) {
	row := q.db.QueryRowContext(ctx, getSubtaskToolcallsStats, subtaskID)
	var i GetSubtaskToolcallsStatsRow
	err := row.Scan(&i.TotalCount, &i.TotalDurationSeconds)
	return i, err
}

const getTaskToolcallsStats = `-- name: GetTaskToolcallsStats :one
SELECT
  COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
  COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
LEFT JOIN subtasks s ON tc.subtask_id = s.id
INNER JOIN tasks t ON tc.task_id = t.id OR s.task_id = t.id
INNER JOIN flows f ON t.flow_id = f.id
WHERE (tc.task_id = $1 OR s.task_id = $1) AND f.deleted_at IS NULL
  AND (tc.subtask_id IS NULL OR s.id IS NOT NULL)
`

type GetTaskToolcallsStatsRow struct {
	TotalCount           int64   `json:"total_count"`
	TotalDurationSeconds float64 `json:"total_duration_seconds"`
}

// Get total execution time and count of toolcalls for a specific task
func (q *Queries) GetTaskToolcallsStats(ctx context.Context, taskID sql.NullInt64) (GetTaskToolcallsStatsRow, error) {
	row := q.db.QueryRowContext(ctx, getTaskToolcallsStats, taskID)
	var i GetTaskToolcallsStatsRow
	err := row.Scan(&i.TotalCount, &i.TotalDurationSeconds)
	return i, err
}

const getToolcallsStatsByDay = `-- name: GetToolcallsStatsByDay :many
WITH bounds AS (
  SELECT
    ((NOW() AT TIME ZONE $1::text)::date - $2::int) AS first_day,
    (NOW() AT TIME ZONE $1::text)::date AS last_day
),
days AS (
  SELECT generate_series(b.first_day, b.last_day, INTERVAL '1 day')::date AS day
  FROM bounds b
),
agg AS (
  SELECT
    (tc.created_at AT TIME ZONE $1::text)::date AS day,
    COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END)::bigint AS total_count,
    SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END)::double precision AS total_duration_seconds
  FROM toolcalls tc
  INNER JOIN flows f ON f.id = tc.flow_id
  WHERE f.deleted_at IS NULL
    AND f.user_id = $3
    -- The coarse bounds keep the index; the exact test repeats the grouping
    -- expression, because an ambiguous local midnight resolves to the later
    -- instant and would drop the earlier hour of that day.
    AND tc.created_at >= (((SELECT first_day FROM bounds) - 1)::timestamp AT TIME ZONE $1::text)
    AND tc.created_at < (((SELECT last_day FROM bounds) + 2)::timestamp AT TIME ZONE $1::text)
    AND (tc.created_at AT TIME ZONE $1::text)::date
        BETWEEN (SELECT first_day FROM bounds) AND (SELECT last_day FROM bounds)
  GROUP BY 1
)
SELECT
  (d.day::timestamp AT TIME ZONE $1::text) AS date,
  COALESCE(a.total_count, 0)::bigint AS total_count,
  COALESCE(a.total_duration_seconds, 0.0)::double precision AS total_duration_seconds
FROM days d
LEFT JOIN agg a ON a.day = d.day
ORDER BY date DESC
`

type GetToolcallsStatsByDayParams struct {
	Tz     string `json:"tz"`
	Days   int32  `json:"days"`
	UserID int64  `json:"user_id"`
}

type GetToolcallsStatsByDayRow struct {
	Date                 time.Time `json:"date"`
	TotalCount           int64     `json:"total_count"`
	TotalDurationSeconds float64   `json:"total_duration_seconds"`
}

// One dense row per calendar day in the caller's timezone, zeros included.
func (q *Queries) GetToolcallsStatsByDay(ctx context.Context, arg GetToolcallsStatsByDayParams) ([]GetToolcallsStatsByDayRow, error) {
	rows, err := q.db.QueryContext(ctx, getToolcallsStatsByDay, arg.Tz, arg.Days, arg.UserID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetToolcallsStatsByDayRow
	for rows.Next() {
		var i GetToolcallsStatsByDayRow
		if err := rows.Scan(&i.Date, &i.TotalCount, &i.TotalDurationSeconds); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getToolcallsStatsByFunction = `-- name: GetToolcallsStatsByFunction :many
SELECT
  tc.name AS function_name,
  COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
  COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds,
  COALESCE(AVG(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE NULL END), 0.0)::double precision AS avg_duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON f.id = tc.flow_id
WHERE f.deleted_at IS NULL AND f.user_id = $1
GROUP BY tc.name
ORDER BY total_duration_seconds DESC
`

type GetToolcallsStatsByFunctionRow struct {
	FunctionName         string  `json:"function_name"`
	TotalCount           int64   `json:"total_count"`
	TotalDurationSeconds float64 `json:"total_duration_seconds"`
	AvgDurationSeconds   float64 `json:"avg_duration_seconds"`
}

// Get toolcalls stats grouped by function name for a user
func (q *Queries) GetToolcallsStatsByFunction(ctx context.Context, userID int64) ([]GetToolcallsStatsByFunctionRow, error) {
	rows, err := q.db.QueryContext(ctx, getToolcallsStatsByFunction, userID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetToolcallsStatsByFunctionRow
	for rows.Next() {
		var i GetToolcallsStatsByFunctionRow
		if err := rows.Scan(
			&i.FunctionName,
			&i.TotalCount,
			&i.TotalDurationSeconds,
			&i.AvgDurationSeconds,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getToolcallsStatsByFunctionForFlow = `-- name: GetToolcallsStatsByFunctionForFlow :many
SELECT
  tc.name AS function_name,
  COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
  COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds,
  COALESCE(AVG(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE NULL END), 0.0)::double precision AS avg_duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON f.id = tc.flow_id
WHERE tc.flow_id = $1 AND f.deleted_at IS NULL
GROUP BY tc.name
ORDER BY total_duration_seconds DESC
`

type GetToolcallsStatsByFunctionForFlowRow struct {
	FunctionName         string  `json:"function_name"`
	TotalCount           int64   `json:"total_count"`
	TotalDurationSeconds float64 `json:"total_duration_seconds"`
	AvgDurationSeconds   float64 `json:"avg_duration_seconds"`
}

// Get toolcalls stats grouped by function name for a specific flow
func (q *Queries) GetToolcallsStatsByFunctionForFlow(ctx context.Context, flowID int64) ([]GetToolcallsStatsByFunctionForFlowRow, error) {
	rows, err := q.db.QueryContext(ctx, getToolcallsStatsByFunctionForFlow, flowID)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []GetToolcallsStatsByFunctionForFlowRow
	for rows.Next() {
		var i GetToolcallsStatsByFunctionForFlowRow
		if err := rows.Scan(
			&i.FunctionName,
			&i.TotalCount,
			&i.TotalDurationSeconds,
			&i.AvgDurationSeconds,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const getUserTotalToolcallsStats = `-- name: GetUserTotalToolcallsStats :one
SELECT
  COALESCE(COUNT(CASE WHEN tc.status IN ('finished', 'failed') THEN 1 END), 0)::bigint AS total_count,
  COALESCE(SUM(CASE WHEN tc.status IN ('finished', 'failed') THEN tc.duration_seconds ELSE 0 END), 0.0)::double precision AS total_duration_seconds
FROM toolcalls tc
INNER JOIN flows f ON f.id = tc.flow_id
WHERE f.deleted_at IS NULL AND f.user_id = $1
`

type GetUserTotalToolcallsStatsRow struct {
	TotalCount           int64   `json:"total_count"`
	TotalDurationSeconds float64 `json:"total_duration_seconds"`
}

// Get total toolcalls stats for a user
func (q *Queries) GetUserTotalToolcallsStats(ctx context.Context, userID int64) (GetUserTotalToolcallsStatsRow, error) {
	row := q.db.QueryRowContext(ctx, getUserTotalToolcallsStats, userID)
	var i GetUserTotalToolcallsStatsRow
	err := row.Scan(&i.TotalCount, &i.TotalDurationSeconds)
	return i, err
}

const updateToolcallFailedResult = `-- name: UpdateToolcallFailedResult :one
UPDATE toolcalls
SET 
  status = 'failed', 
  result = $1,
  duration_seconds = duration_seconds + $2
WHERE id = $3
RETURNING id, call_id, status, name, args, result, flow_id, task_id, subtask_id, created_at, updated_at, duration_seconds
`

type UpdateToolcallFailedResultParams struct {
	Result          string  `json:"result"`
	DurationSeconds float64 `json:"duration_seconds"`
	ID              int64   `json:"id"`
}

func (q *Queries) UpdateToolcallFailedResult(ctx context.Context, arg UpdateToolcallFailedResultParams) (Toolcall, error) {
	row := q.db.QueryRowContext(ctx, updateToolcallFailedResult, arg.Result, arg.DurationSeconds, arg.ID)
	var i Toolcall
	err := row.Scan(
		&i.ID,
		&i.CallID,
		&i.Status,
		&i.Name,
		&i.Args,
		&i.Result,
		&i.FlowID,
		&i.TaskID,
		&i.SubtaskID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DurationSeconds,
	)
	return i, err
}

const updateToolcallFinishedResult = `-- name: UpdateToolcallFinishedResult :one
UPDATE toolcalls
SET 
  status = 'finished', 
  result = $1,
  duration_seconds = duration_seconds + $2
WHERE id = $3
RETURNING id, call_id, status, name, args, result, flow_id, task_id, subtask_id, created_at, updated_at, duration_seconds
`

type UpdateToolcallFinishedResultParams struct {
	Result          string  `json:"result"`
	DurationSeconds float64 `json:"duration_seconds"`
	ID              int64   `json:"id"`
}

func (q *Queries) UpdateToolcallFinishedResult(ctx context.Context, arg UpdateToolcallFinishedResultParams) (Toolcall, error) {
	row := q.db.QueryRowContext(ctx, updateToolcallFinishedResult, arg.Result, arg.DurationSeconds, arg.ID)
	var i Toolcall
	err := row.Scan(
		&i.ID,
		&i.CallID,
		&i.Status,
		&i.Name,
		&i.Args,
		&i.Result,
		&i.FlowID,
		&i.TaskID,
		&i.SubtaskID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DurationSeconds,
	)
	return i, err
}

const updateToolcallStatus = `-- name: UpdateToolcallStatus :one
UPDATE toolcalls
SET 
  status = $1,
  duration_seconds = duration_seconds + $2
WHERE id = $3
RETURNING id, call_id, status, name, args, result, flow_id, task_id, subtask_id, created_at, updated_at, duration_seconds
`

type UpdateToolcallStatusParams struct {
	Status          ToolcallStatus `json:"status"`
	DurationSeconds float64        `json:"duration_seconds"`
	ID              int64          `json:"id"`
}

func (q *Queries) UpdateToolcallStatus(ctx context.Context, arg UpdateToolcallStatusParams) (Toolcall, error) {
	row := q.db.QueryRowContext(ctx, updateToolcallStatus, arg.Status, arg.DurationSeconds, arg.ID)
	var i Toolcall
	err := row.Scan(
		&i.ID,
		&i.CallID,
		&i.Status,
		&i.Name,
		&i.Args,
		&i.Result,
		&i.FlowID,
		&i.TaskID,
		&i.SubtaskID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.DurationSeconds,
	)
	return i, err
}
