// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.30.0
// source: geospatial.sql

package database

import (
	"context"

	"github.com/jackc/pgx/v5/pgtype"
)

const CountRequestsNearby = `-- name: CountRequestsNearby :one

SELECT COUNT(*) FROM requests r
WHERE r.deleted_at IS NULL
    AND r.status = $3
    AND ST_DWithin(
        r.location,
        ST_SetSRID(ST_MakePoint($1, $2), 4326)::geography,
        $4
    )
`

type CountRequestsNearbyParams struct {
	StMakepoint   interface{}       `json:"st_makepoint"`
	StMakepoint_2 interface{}       `json:"st_makepoint_2"`
	Status        NullRequestStatus `json:"status"`
	StDwithin     interface{}       `json:"st_dwithin"`
}

// ============================================================================
// Подсчет заявок поблизости
// ============================================================================
func (q *Queries) CountRequestsNearby(ctx context.Context, arg CountRequestsNearbyParams) (int64, error) {
	row := q.db.QueryRow(ctx, CountRequestsNearby,
		arg.StMakepoint,
		arg.StMakepoint_2,
		arg.Status,
		arg.StDwithin,
	)
	var count int64
	err := row.Scan(&count)
	return count, err
}

const FindNearestRequestsForVolunteer = `-- name: FindNearestRequestsForVolunteer :many

SELECT
    r.id,
    r.title,
    r.description,
    r.urgency,
    r.status,
    r.created_at,
    ST_Y(r.location::geometry) as latitude,
    ST_X(r.location::geometry) as longitude,
    ST_Distance(
        r.location,
        (SELECT u.location FROM users u WHERE u.id = $1)
    ) as distance_meters,
    rt.name as request_type_name,
    rt.icon as request_type_icon
FROM requests r
JOIN request_types rt ON rt.id = r.request_type_id
WHERE r.deleted_at IS NULL
    AND r.status = 'approved'
    AND r.assigned_volunteer_id IS NULL
    AND ST_DWithin(
        r.location,
        (SELECT u.location FROM users u WHERE u.id = $1),
        $2
    )
ORDER BY
    CASE r.urgency
        WHEN 'urgent' THEN 1
        WHEN 'high' THEN 2
        WHEN 'medium' THEN 3
        ELSE 4
    END,
    distance_meters
LIMIT $3
`

type FindNearestRequestsForVolunteerParams struct {
	ID        int64       `json:"id"`
	StDwithin interface{} `json:"st_dwithin"`
	Limit     int32       `json:"limit"`
}

type FindNearestRequestsForVolunteerRow struct {
	ID              int64              `json:"id"`
	Title           string             `json:"title"`
	Description     string             `json:"description"`
	Urgency         pgtype.Text        `json:"urgency"`
	Status          NullRequestStatus  `json:"status"`
	CreatedAt       pgtype.Timestamptz `json:"created_at"`
	Latitude        interface{}        `json:"latitude"`
	Longitude       interface{}        `json:"longitude"`
	DistanceMeters  interface{}        `json:"distance_meters"`
	RequestTypeName string             `json:"request_type_name"`
	RequestTypeIcon pgtype.Text        `json:"request_type_icon"`
}

// ============================================================================
// Поиск ближайших заявок для волонтера
// ============================================================================
func (q *Queries) FindNearestRequestsForVolunteer(ctx context.Context, arg FindNearestRequestsForVolunteerParams) ([]FindNearestRequestsForVolunteerRow, error) {
	rows, err := q.db.Query(ctx, FindNearestRequestsForVolunteer, arg.ID, arg.StDwithin, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []FindNearestRequestsForVolunteerRow{}
	for rows.Next() {
		var i FindNearestRequestsForVolunteerRow
		if err := rows.Scan(
			&i.ID,
			&i.Title,
			&i.Description,
			&i.Urgency,
			&i.Status,
			&i.CreatedAt,
			&i.Latitude,
			&i.Longitude,
			&i.DistanceMeters,
			&i.RequestTypeName,
			&i.RequestTypeIcon,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const FindRequestsInBounds = `-- name: FindRequestsInBounds :many

SELECT
    r.id,
    r.title,
    r.urgency,
    r.status,
    r.created_at,
    ST_Y(r.location::geometry) as latitude,
    ST_X(r.location::geometry) as longitude,
    rt.icon as request_type_icon,
    rt.name as request_type_name
FROM requests r
JOIN request_types rt ON rt.id = r.request_type_id
WHERE r.deleted_at IS NULL
    AND r.status::text = ANY($1::text[])
    AND ST_Within(
        r.location::geometry,
        ST_MakeEnvelope($2, $3, $4, $5, 4326)
    )
ORDER BY r.created_at DESC
LIMIT 200
`

type FindRequestsInBoundsParams struct {
	Column1          []string    `json:"column_1"`
	StMakeenvelope   interface{} `json:"st_makeenvelope"`
	StMakeenvelope_2 interface{} `json:"st_makeenvelope_2"`
	StMakeenvelope_3 interface{} `json:"st_makeenvelope_3"`
	StMakeenvelope_4 interface{} `json:"st_makeenvelope_4"`
}

type FindRequestsInBoundsRow struct {
	ID              int64              `json:"id"`
	Title           string             `json:"title"`
	Urgency         pgtype.Text        `json:"urgency"`
	Status          NullRequestStatus  `json:"status"`
	CreatedAt       pgtype.Timestamptz `json:"created_at"`
	Latitude        interface{}        `json:"latitude"`
	Longitude       interface{}        `json:"longitude"`
	RequestTypeIcon pgtype.Text        `json:"request_type_icon"`
	RequestTypeName string             `json:"request_type_name"`
}

// ============================================================================
// Поиск заявок в прямоугольной области (для карты)
// ============================================================================
func (q *Queries) FindRequestsInBounds(ctx context.Context, arg FindRequestsInBoundsParams) ([]FindRequestsInBoundsRow, error) {
	rows, err := q.db.Query(ctx, FindRequestsInBounds,
		arg.Column1,
		arg.StMakeenvelope,
		arg.StMakeenvelope_2,
		arg.StMakeenvelope_3,
		arg.StMakeenvelope_4,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []FindRequestsInBoundsRow{}
	for rows.Next() {
		var i FindRequestsInBoundsRow
		if err := rows.Scan(
			&i.ID,
			&i.Title,
			&i.Urgency,
			&i.Status,
			&i.CreatedAt,
			&i.Latitude,
			&i.Longitude,
			&i.RequestTypeIcon,
			&i.RequestTypeName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const FindRequestsNearby = `-- name: FindRequestsNearby :many


SELECT
    r.id,
    r.title,
    r.description,
    r.address,
    r.city,
    r.urgency,
    r.status,
    r.created_at,
    r.desired_completion_date,
    ST_Y(r.location::geometry) as latitude,
    ST_X(r.location::geometry) as longitude,
    ST_Distance(
        r.location,
        ST_SetSRID(ST_MakePoint($1, $2), 4326)::geography
    ) as distance_meters,
    rt.name as request_type_name,
    rt.icon as request_type_icon,
    (u.first_name || ' ' || u.last_name) as requester_name
FROM requests r
JOIN request_types rt ON rt.id = r.request_type_id
JOIN users u ON u.id = r.requester_id
WHERE r.deleted_at IS NULL
    AND r.status::text = ANY($3::text[])
    AND ST_DWithin(
        r.location,
        ST_SetSRID(ST_MakePoint($1, $2), 4326)::geography,
        $4
    )
ORDER BY distance_meters
LIMIT $5 OFFSET $6
`

type FindRequestsNearbyParams struct {
	StMakepoint   interface{} `json:"st_makepoint"`
	StMakepoint_2 interface{} `json:"st_makepoint_2"`
	Column3       []string    `json:"column_3"`
	StDwithin     interface{} `json:"st_dwithin"`
	Limit         int32       `json:"limit"`
	Offset        int32       `json:"offset"`
}

type FindRequestsNearbyRow struct {
	ID                    int64              `json:"id"`
	Title                 string             `json:"title"`
	Description           string             `json:"description"`
	Address               string             `json:"address"`
	City                  pgtype.Text        `json:"city"`
	Urgency               pgtype.Text        `json:"urgency"`
	Status                NullRequestStatus  `json:"status"`
	CreatedAt             pgtype.Timestamptz `json:"created_at"`
	DesiredCompletionDate pgtype.Timestamptz `json:"desired_completion_date"`
	Latitude              interface{}        `json:"latitude"`
	Longitude             interface{}        `json:"longitude"`
	DistanceMeters        interface{}        `json:"distance_meters"`
	RequestTypeName       string             `json:"request_type_name"`
	RequestTypeIcon       pgtype.Text        `json:"request_type_icon"`
	RequesterName         interface{}        `json:"requester_name"`
}

// Фаза 2B: Геопространственные запросы (ВЫСОКИЙ ПРИОРИТЕТ)
// PostGIS запросы для поиска заявок по геолокации
// ============================================================================
// Поиск заявок рядом с точкой
// ============================================================================
func (q *Queries) FindRequestsNearby(ctx context.Context, arg FindRequestsNearbyParams) ([]FindRequestsNearbyRow, error) {
	rows, err := q.db.Query(ctx, FindRequestsNearby,
		arg.StMakepoint,
		arg.StMakepoint_2,
		arg.Column3,
		arg.StDwithin,
		arg.Limit,
		arg.Offset,
	)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []FindRequestsNearbyRow{}
	for rows.Next() {
		var i FindRequestsNearbyRow
		if err := rows.Scan(
			&i.ID,
			&i.Title,
			&i.Description,
			&i.Address,
			&i.City,
			&i.Urgency,
			&i.Status,
			&i.CreatedAt,
			&i.DesiredCompletionDate,
			&i.Latitude,
			&i.Longitude,
			&i.DistanceMeters,
			&i.RequestTypeName,
			&i.RequestTypeIcon,
			&i.RequesterName,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const FindVolunteersNearRequest = `-- name: FindVolunteersNearRequest :many

SELECT
    u.id,
    (u.first_name || ' ' || u.last_name) as full_name,
    u.avatar_url,
    u.volunteer_rating,
    u.completed_requests_count,
    ST_Y(u.location::geometry) as latitude,
    ST_X(u.location::geometry) as longitude,
    ST_Distance(
        u.location,
        (SELECT req.location FROM requests req WHERE req.id = $1)
    ) as distance_meters
FROM users u
JOIN user_roles ur ON ur.user_id = u.id
JOIN roles r ON r.id = ur.role_id
WHERE r.name = 'volunteer'
    AND u.deleted_at IS NULL
    AND u.is_blocked = FALSE
    AND u.location IS NOT NULL
    AND ST_DWithin(
        u.location,
        (SELECT req.location FROM requests req WHERE req.id = $1),
        $2
    )
ORDER BY distance_meters
LIMIT $3
`

type FindVolunteersNearRequestParams struct {
	ID        int64       `json:"id"`
	StDwithin interface{} `json:"st_dwithin"`
	Limit     int32       `json:"limit"`
}

type FindVolunteersNearRequestRow struct {
	ID                     int64          `json:"id"`
	FullName               interface{}    `json:"full_name"`
	AvatarUrl              pgtype.Text    `json:"avatar_url"`
	VolunteerRating        pgtype.Numeric `json:"volunteer_rating"`
	CompletedRequestsCount pgtype.Int4    `json:"completed_requests_count"`
	Latitude               interface{}    `json:"latitude"`
	Longitude              interface{}    `json:"longitude"`
	DistanceMeters         interface{}    `json:"distance_meters"`
}

// ============================================================================
// Поиск волонтеров рядом с заявкой
// ============================================================================
func (q *Queries) FindVolunteersNearRequest(ctx context.Context, arg FindVolunteersNearRequestParams) ([]FindVolunteersNearRequestRow, error) {
	rows, err := q.db.Query(ctx, FindVolunteersNearRequest, arg.ID, arg.StDwithin, arg.Limit)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	items := []FindVolunteersNearRequestRow{}
	for rows.Next() {
		var i FindVolunteersNearRequestRow
		if err := rows.Scan(
			&i.ID,
			&i.FullName,
			&i.AvatarUrl,
			&i.VolunteerRating,
			&i.CompletedRequestsCount,
			&i.Latitude,
			&i.Longitude,
			&i.DistanceMeters,
		); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}
