-- +goose Up
-- +goose StatementBegin

-- =========================================
-- ФУНКЦИЯ: accept_volunteer_response
-- Принятие отклика волонтера с назначением на заявку
-- =========================================
CREATE OR REPLACE FUNCTION accept_volunteer_response(
    p_response_id BIGINT,
    p_requester_id BIGINT
)
RETURNS TABLE (
    success BOOLEAN,
    message TEXT,
    out_request_id BIGINT,
    out_volunteer_id BIGINT
) AS $$
DECLARE
    v_request_id BIGINT;
    v_volunteer_id BIGINT;
    v_request_status request_status;
    v_response_status VARCHAR(20);
    v_assigned_volunteer_id BIGINT;
    v_request_requester_id BIGINT;
BEGIN
    -- Получаем информацию об отклике и связанной заявке
    SELECT
        vr.request_id,
        vr.volunteer_id,
        vr.status,
        r.status,
        r.assigned_volunteer_id,
        r.requester_id
    INTO
        v_request_id,
        v_volunteer_id,
        v_response_status,
        v_request_status,
        v_assigned_volunteer_id,
        v_request_requester_id
    FROM volunteer_responses vr
    JOIN requests r ON r.id = vr.request_id
    WHERE vr.id = p_response_id
    AND r.deleted_at IS NULL;

    -- Проверка: отклик существует
    IF v_request_id IS NULL THEN
        RETURN QUERY SELECT FALSE, 'Volunteer response not found'::TEXT, NULL::BIGINT, NULL::BIGINT;
        RETURN;
    END IF;

    -- Проверка: заявка принадлежит заявителю
    IF v_request_requester_id != p_requester_id THEN
        RETURN QUERY SELECT FALSE, 'You are not the owner of this request'::TEXT, v_request_id, v_volunteer_id;
        RETURN;
    END IF;

    -- Проверка: заявка в статусе 'approved'
    IF v_request_status != 'approved' THEN
        RETURN QUERY SELECT FALSE, format('Request must be in approved status, current status: %s', v_request_status)::TEXT, v_request_id, v_volunteer_id;
        RETURN;
    END IF;

    -- Проверка: отклик в статусе 'pending'
    IF v_response_status != 'pending' THEN
        RETURN QUERY SELECT FALSE, format('Response must be in pending status, current status: %s', v_response_status)::TEXT, v_request_id, v_volunteer_id;
        RETURN;
    END IF;

    -- Проверка: заявка еще не взята другим волонтером
    IF v_assigned_volunteer_id IS NOT NULL THEN
        RETURN QUERY SELECT FALSE, 'Request already assigned to another volunteer'::TEXT, v_request_id, v_volunteer_id;
        RETURN;
    END IF;

    -- Все проверки пройдены, выполняем операцию

    -- 1. Принимаем отклик
    UPDATE volunteer_responses SET
        status = 'accepted',
        accepted_at = CURRENT_TIMESTAMP,
        updated_at = CURRENT_TIMESTAMP
    WHERE id = p_response_id;

    -- 2. Назначаем волонтера на заявку и меняем статус
    UPDATE requests SET
        assigned_volunteer_id = v_volunteer_id,
        status = 'in_progress',
        updated_at = CURRENT_TIMESTAMP
    WHERE id = v_request_id;

    -- 3. Отклоняем все остальные отклики на эту заявку
    UPDATE volunteer_responses SET
        status = 'rejected',
        rejected_at = CURRENT_TIMESTAMP,
        updated_at = CURRENT_TIMESTAMP
    WHERE request_id = v_request_id
    AND id != p_response_id
    AND status = 'pending';

    -- Триггер log_request_status_change автоматически создаст запись в request_status_history

    RETURN QUERY SELECT TRUE, 'Volunteer response accepted successfully'::TEXT, v_request_id, v_volunteer_id;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION accept_volunteer_response IS 'Атомарное принятие отклика волонтера: обновление статусов заявки и отклика, отклонение остальных откликов. Предотвращает race conditions.';

-- =========================================
-- ФУНКЦИЯ: complete_request_with_rating
-- Завершение заявки с обязательным выставлением рейтинга
-- =========================================
CREATE OR REPLACE FUNCTION complete_request_with_rating(
    p_request_id BIGINT,
    p_requester_id BIGINT,
    p_rating INTEGER,
    p_comment TEXT DEFAULT NULL
)
RETURNS TABLE (
    success BOOLEAN,
    message TEXT,
    out_rating_id BIGINT
) AS $$
DECLARE
    v_request_status request_status;
    v_volunteer_id BIGINT;
    v_requester_id BIGINT;
    v_response_id BIGINT;
    v_rating_id BIGINT;
BEGIN
    -- Получаем информацию о заявке
    SELECT
        r.status,
        r.assigned_volunteer_id,
        r.requester_id
    INTO
        v_request_status,
        v_volunteer_id,
        v_requester_id
    FROM requests r
    WHERE r.id = p_request_id
    AND r.deleted_at IS NULL;

    -- Проверка: заявка существует
    IF v_request_status IS NULL THEN
        RETURN QUERY SELECT FALSE, 'Request not found'::TEXT, 0::BIGINT;
        RETURN;
    END IF;

    -- Проверка: заявка принадлежит заявителю
    IF v_requester_id != p_requester_id THEN
        RETURN QUERY SELECT FALSE, 'You are not the owner of this request'::TEXT, 0::BIGINT;
        RETURN;
    END IF;

    -- Проверка: заявка в статусе 'in_progress'
    IF v_request_status != 'in_progress' THEN
        RETURN QUERY SELECT FALSE, format('Request must be in in_progress status, current status: %s', v_request_status)::TEXT, 0::BIGINT;
        RETURN;
    END IF;

    -- Проверка: есть назначенный волонтер
    IF v_volunteer_id IS NULL THEN
        RETURN QUERY SELECT FALSE, 'Request has no assigned volunteer'::TEXT, 0::BIGINT;
        RETURN;
    END IF;

    -- Проверка: рейтинг от 1 до 5
    IF p_rating < 1 OR p_rating > 5 THEN
        RETURN QUERY SELECT FALSE, 'Rating must be between 1 and 5'::TEXT, 0::BIGINT;
        RETURN;
    END IF;

    -- Все проверки пройдены, выполняем операцию

    -- 1. Завершаем заявку
    UPDATE requests SET
        status = 'completed',
        completed_at = CURRENT_TIMESTAMP,
        updated_at = CURRENT_TIMESTAMP
    WHERE id = p_request_id;

    -- 2. Получаем ID отклика (для связи с рейтингом)
    SELECT id INTO v_response_id
    FROM volunteer_responses
    WHERE request_id = p_request_id
    AND volunteer_id = v_volunteer_id
    AND status = 'accepted'
    LIMIT 1;

    -- 3. Создаем рейтинг
    INSERT INTO ratings (
        volunteer_response_id,
        volunteer_id,
        requester_id,
        request_id,
        rating,
        comment
    ) VALUES (
        v_response_id,
        v_volunteer_id,
        p_requester_id,
        p_request_id,
        p_rating,
        p_comment
    ) RETURNING id INTO v_rating_id;

    -- Триггер update_volunteer_rating автоматически пересчитает рейтинг волонтера
    -- Триггер log_request_status_change автоматически создаст запись в request_status_history

    RETURN QUERY SELECT TRUE, 'Request completed and rating saved successfully'::TEXT, v_rating_id;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION complete_request_with_rating IS 'Атомарное завершение заявки с обязательным выставлением рейтинга волонтеру. Триггер автоматически пересчитает средний рейтинг волонтера.';

-- =========================================
-- ФУНКЦИЯ: moderate_request
-- Универсальная функция модерации заявок
-- =========================================
CREATE OR REPLACE FUNCTION moderate_request(
    p_request_id BIGINT,
    p_moderator_id BIGINT,
    p_action TEXT, -- 'approve' или 'reject'
    p_comment TEXT DEFAULT NULL
)
RETURNS TABLE (
    success BOOLEAN,
    message TEXT
) AS $$
DECLARE
    v_request_status request_status;
    v_has_permission BOOLEAN;
    v_new_status request_status;
BEGIN
    -- Проверка: модератор имеет право модерировать
    SELECT has_permission(p_moderator_id, 'moderate_requests') INTO v_has_permission;

    IF NOT v_has_permission THEN
        RETURN QUERY SELECT FALSE, 'You do not have permission to moderate requests'::TEXT;
        RETURN;
    END IF;

    -- Получаем текущий статус заявки
    SELECT status INTO v_request_status
    FROM requests
    WHERE id = p_request_id
    AND deleted_at IS NULL;

    -- Проверка: заявка существует
    IF v_request_status IS NULL THEN
        RETURN QUERY SELECT FALSE, 'Request not found'::TEXT;
        RETURN;
    END IF;

    -- Проверка: заявка в статусе 'pending_moderation'
    IF v_request_status != 'pending_moderation' THEN
        RETURN QUERY SELECT FALSE, format('Request must be in pending_moderation status, current status: %s', v_request_status)::TEXT;
        RETURN;
    END IF;

    -- Определяем новый статус
    IF p_action = 'approve' THEN
        v_new_status := 'approved';
    ELSIF p_action = 'reject' THEN
        v_new_status := 'rejected';

        -- При отклонении комментарий обязателен
        IF p_comment IS NULL OR trim(p_comment) = '' THEN
            RETURN QUERY SELECT FALSE, 'Comment is required when rejecting a request'::TEXT;
            RETURN;
        END IF;
    ELSE
        RETURN QUERY SELECT FALSE, format('Invalid action: %s. Must be approve or reject', p_action)::TEXT;
        RETURN;
    END IF;

    -- Все проверки пройдены, выполняем модерацию

    UPDATE requests SET
        status = v_new_status,
        moderated_by = p_moderator_id,
        moderated_at = CURRENT_TIMESTAMP,
        moderation_comment = p_comment,
        updated_at = CURRENT_TIMESTAMP
    WHERE id = p_request_id;

    -- Триггер audit_moderation_action автоматически создаст запись в moderator_actions
    -- Триггер log_request_status_change автоматически создаст запись в request_status_history

    RETURN QUERY SELECT TRUE, format('Request %s successfully', p_action)::TEXT;
END;
$$ LANGUAGE plpgsql;

COMMENT ON FUNCTION moderate_request IS 'Универсальная функция модерации заявок с проверкой прав, валидацией статуса и автоматическим аудитом через триггеры.';

-- +goose StatementEnd

-- +goose Down
-- +goose StatementBegin

DROP FUNCTION IF EXISTS moderate_request;
DROP FUNCTION IF EXISTS complete_request_with_rating;
DROP FUNCTION IF EXISTS accept_volunteer_response;

-- +goose StatementEnd
