-- +goose Up
-- +goose StatementBegin

-- =========================================
-- ФУНКЦИЯ: find_requests_nearby - Геопоиск заявок
-- =========================================
CREATE OR REPLACE FUNCTION find_requests_nearby(
    lat DOUBLE PRECISION,
    lon DOUBLE PRECISION,
    radius_meters INTEGER DEFAULT 5000,
    req_status request_status DEFAULT 'approved'
)
RETURNS TABLE (
    id BIGINT,
    title VARCHAR(255),
    description TEXT,
    address TEXT,
    distance_meters DOUBLE PRECISION,
    urgency VARCHAR(20),
    created_at TIMESTAMP WITH TIME ZONE
) AS $$
BEGIN
    RETURN QUERY
    SELECT
        r.id,
        r.title,
        r.description,
        r.address,
        ST_Distance(
            r.location,
            ST_SetSRID(ST_MakePoint(lon, lat), 4326)::geography
        ) as distance_meters,
        r.urgency,
        r.created_at
    FROM requests r
    WHERE
        r.status = req_status
        AND r.deleted_at IS NULL
        AND ST_DWithin(
            r.location,
            ST_SetSRID(ST_MakePoint(lon, lat), 4326)::geography,
            radius_meters
        )
    ORDER BY distance_meters;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION find_requests_nearby IS 'Поиск заявок в радиусе от точки с возвратом расстояния в метрах';

-- =========================================
-- ФУНКЦИЯ: cleanup_expired_tokens - Очистка истёкших токенов
-- =========================================
CREATE OR REPLACE FUNCTION cleanup_expired_tokens()
RETURNS INTEGER AS $$
DECLARE
    deleted_count INTEGER;
BEGIN
    -- Удаляем истёкшие refresh токены
    DELETE FROM refresh_tokens
    WHERE expires_at < CURRENT_TIMESTAMP
    AND revoked = FALSE;

    GET DIAGNOSTICS deleted_count = ROW_COUNT;

    -- Удаляем истёкшие сессии
    DELETE FROM user_sessions
    WHERE expires_at < CURRENT_TIMESTAMP;

    RETURN deleted_count;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION cleanup_expired_tokens IS 'Удаление истёкших токенов и сессий. Рекомендуется запускать по расписанию';

-- =========================================
-- ФУНКЦИЯ: calculate_distance_meters - Расчёт расстояния между точками
-- =========================================
CREATE OR REPLACE FUNCTION calculate_distance_meters(
    lat1 DOUBLE PRECISION,
    lon1 DOUBLE PRECISION,
    lat2 DOUBLE PRECISION,
    lon2 DOUBLE PRECISION
)
RETURNS DOUBLE PRECISION AS $$
BEGIN
    RETURN ST_Distance(
        ST_SetSRID(ST_MakePoint(lon1, lat1), 4326)::geography,
        ST_SetSRID(ST_MakePoint(lon2, lat2), 4326)::geography
    );
END;
$$ LANGUAGE plpgsql IMMUTABLE;

COMMENT ON FUNCTION calculate_distance_meters IS 'Расчёт расстояния между двумя точками в метрах';

-- =========================================
-- ФУНКЦИЯ: get_user_permissions - Получение прав пользователя
-- =========================================
CREATE OR REPLACE FUNCTION get_user_permissions(p_user_id BIGINT)
RETURNS TABLE (
    permission_name VARCHAR(100),
    resource VARCHAR(50),
    action VARCHAR(50)
) AS $$
BEGIN
    RETURN QUERY
    SELECT DISTINCT
        p.name,
        p.resource,
        p.action
    FROM users u
    JOIN user_roles ur ON ur.user_id = u.id
    JOIN role_permissions rp ON rp.role_id = ur.role_id
    JOIN permissions p ON p.id = rp.permission_id
    WHERE u.id = p_user_id
    AND u.deleted_at IS NULL
    AND u.is_blocked = FALSE;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION get_user_permissions IS 'Получение всех разрешений пользователя через его роли';

-- =========================================
-- ФУНКЦИЯ: has_permission - Проверка наличия разрешения
-- =========================================
CREATE OR REPLACE FUNCTION has_permission(
    p_user_id BIGINT,
    p_permission_name VARCHAR(100)
)
RETURNS BOOLEAN AS $$
BEGIN
    RETURN EXISTS(
        SELECT 1
        FROM users u
        JOIN user_roles ur ON ur.user_id = u.id
        JOIN role_permissions rp ON rp.role_id = ur.role_id
        JOIN permissions p ON p.id = rp.permission_id
        WHERE u.id = p_user_id
        AND p.name = p_permission_name
        AND u.deleted_at IS NULL
        AND u.is_blocked = FALSE
    );
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION has_permission IS 'Быстрая проверка наличия конкретного разрешения у пользователя';

-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin

DROP FUNCTION IF EXISTS has_permission;
DROP FUNCTION IF EXISTS get_user_permissions;
DROP FUNCTION IF EXISTS calculate_distance_meters;
DROP FUNCTION IF EXISTS cleanup_expired_tokens;
DROP FUNCTION IF EXISTS find_requests_nearby;

-- +goose StatementEnd
