-- Forum Votes & Reputation Migration for BroadcastBeat
-- Adds upvote/downvote on threads and replies, and reputation points on user_profiles

-- ============================================================
-- 1. ADD REPUTATION COLUMN TO USER_PROFILES
-- ============================================================
ALTER TABLE public.user_profiles
ADD COLUMN IF NOT EXISTS reputation INTEGER DEFAULT 0;

-- ============================================================
-- 2. FORUM VOTES TABLE
-- ============================================================
CREATE TABLE IF NOT EXISTS public.forum_votes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES public.user_profiles(id) ON DELETE CASCADE,
    target_type TEXT NOT NULL CHECK (target_type IN ('thread', 'reply')),
    target_id UUID NOT NULL,
    vote_value SMALLINT NOT NULL CHECK (vote_value IN (1, -1)),
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

-- Unique: one vote per user per target
CREATE UNIQUE INDEX IF NOT EXISTS idx_forum_votes_unique
ON public.forum_votes (user_id, target_type, target_id);

CREATE INDEX IF NOT EXISTS idx_forum_votes_target
ON public.forum_votes (target_type, target_id);

CREATE INDEX IF NOT EXISTS idx_forum_votes_user_id
ON public.forum_votes (user_id);

-- ============================================================
-- 3. ADD VOTE SCORE COLUMNS TO THREADS AND REPLIES
-- ============================================================
ALTER TABLE public.forum_threads
ADD COLUMN IF NOT EXISTS upvotes INTEGER DEFAULT 0,
ADD COLUMN IF NOT EXISTS downvotes INTEGER DEFAULT 0,
ADD COLUMN IF NOT EXISTS vote_score INTEGER DEFAULT 0;

ALTER TABLE public.forum_replies
ADD COLUMN IF NOT EXISTS upvotes INTEGER DEFAULT 0,
ADD COLUMN IF NOT EXISTS downvotes INTEGER DEFAULT 0,
ADD COLUMN IF NOT EXISTS vote_score INTEGER DEFAULT 0;

-- ============================================================
-- 4. FUNCTIONS
-- ============================================================

-- Recalculate vote counts on thread/reply after vote change
CREATE OR REPLACE FUNCTION public.update_vote_counts()
RETURNS TRIGGER
LANGUAGE plpgsql
SECURITY DEFINER
AS $$
DECLARE
    v_target_type TEXT;
    v_target_id UUID;
    v_up INTEGER;
    v_down INTEGER;
    v_author_id UUID;
    v_old_vote SMALLINT := 0;
    v_new_vote SMALLINT := 0;
    v_rep_delta INTEGER := 0;
BEGIN
    -- Determine target info
    IF TG_OP = 'DELETE' THEN
        v_target_type := OLD.target_type;
        v_target_id := OLD.target_id;
        v_old_vote := OLD.vote_value;
    ELSIF TG_OP = 'INSERT' THEN
        v_target_type := NEW.target_type;
        v_target_id := NEW.target_id;
        v_new_vote := NEW.vote_value;
    ELSIF TG_OP = 'UPDATE' THEN
        v_target_type := NEW.target_type;
        v_target_id := NEW.target_id;
        v_old_vote := OLD.vote_value;
        v_new_vote := NEW.vote_value;
    END IF;

    -- Recalculate vote totals
    SELECT
        COALESCE(SUM(CASE WHEN vote_value = 1 THEN 1 ELSE 0 END), 0),
        COALESCE(SUM(CASE WHEN vote_value = -1 THEN 1 ELSE 0 END), 0)
    INTO v_up, v_down
    FROM public.forum_votes
    WHERE target_type = v_target_type AND target_id = v_target_id;

    -- Update the appropriate table
    IF v_target_type = 'thread' THEN
        UPDATE public.forum_threads
        SET upvotes = v_up,
            downvotes = v_down,
            vote_score = v_up - v_down,
            updated_at = CURRENT_TIMESTAMP
        WHERE id = v_target_id;

        SELECT author_id INTO v_author_id
        FROM public.forum_threads WHERE id = v_target_id LIMIT 1;
    ELSIF v_target_type = 'reply' THEN
        UPDATE public.forum_replies
        SET upvotes = v_up,
            downvotes = v_down,
            vote_score = v_up - v_down,
            updated_at = CURRENT_TIMESTAMP
        WHERE id = v_target_id;

        SELECT author_id INTO v_author_id
        FROM public.forum_replies WHERE id = v_target_id LIMIT 1;
    END IF;

    -- Update author reputation (only for authenticated authors)
    IF v_author_id IS NOT NULL THEN
        -- Calculate reputation delta: upvote = +10, downvote = -2
        v_rep_delta := (v_new_vote - v_old_vote) * CASE
            WHEN (v_new_vote > 0 OR v_old_vote > 0) THEN 10
            ELSE 2
        END;

        -- More precise: +10 per upvote gained, -10 per upvote lost, -2 per downvote gained, +2 per downvote lost
        v_rep_delta := 0;
        IF v_new_vote = 1 AND v_old_vote = 0 THEN v_rep_delta := 10; END IF;
        IF v_new_vote = 0 AND v_old_vote = 1 THEN v_rep_delta := -10; END IF;
        IF v_new_vote = -1 AND v_old_vote = 0 THEN v_rep_delta := -2; END IF;
        IF v_new_vote = 0 AND v_old_vote = -1 THEN v_rep_delta := 2; END IF;
        IF v_new_vote = 1 AND v_old_vote = -1 THEN v_rep_delta := 12; END IF;
        IF v_new_vote = -1 AND v_old_vote = 1 THEN v_rep_delta := -12; END IF;

        IF v_rep_delta != 0 THEN
            UPDATE public.user_profiles
            SET reputation = GREATEST(0, COALESCE(reputation, 0) + v_rep_delta)
            WHERE id = v_author_id;
        END IF;
    END IF;

    RETURN COALESCE(NEW, OLD);
END;
$$;

-- ============================================================
-- 5. ENABLE RLS
-- ============================================================
ALTER TABLE public.forum_votes ENABLE ROW LEVEL SECURITY;

-- ============================================================
-- 6. RLS POLICIES
-- ============================================================

-- Public can read all votes (for counts)
DROP POLICY IF EXISTS "public_read_forum_votes" ON public.forum_votes;
CREATE POLICY "public_read_forum_votes"
ON public.forum_votes FOR SELECT TO public USING (true);

-- Authenticated users can insert their own votes
DROP POLICY IF EXISTS "authenticated_insert_forum_votes" ON public.forum_votes;
CREATE POLICY "authenticated_insert_forum_votes"
ON public.forum_votes FOR INSERT TO authenticated
WITH CHECK (user_id = auth.uid());

-- Users can update their own votes
DROP POLICY IF EXISTS "users_update_own_forum_votes" ON public.forum_votes;
CREATE POLICY "users_update_own_forum_votes"
ON public.forum_votes FOR UPDATE TO authenticated
USING (user_id = auth.uid())
WITH CHECK (user_id = auth.uid());

-- Users can delete their own votes
DROP POLICY IF EXISTS "users_delete_own_forum_votes" ON public.forum_votes;
CREATE POLICY "users_delete_own_forum_votes"
ON public.forum_votes FOR DELETE TO authenticated
USING (user_id = auth.uid());

-- Service role full access
DROP POLICY IF EXISTS "service_role_manage_forum_votes" ON public.forum_votes;
CREATE POLICY "service_role_manage_forum_votes"
ON public.forum_votes FOR ALL TO service_role USING (true) WITH CHECK (true);

-- ============================================================
-- 7. TRIGGERS
-- ============================================================
DROP TRIGGER IF EXISTS on_forum_vote_change ON public.forum_votes;
CREATE TRIGGER on_forum_vote_change
AFTER INSERT OR UPDATE OR DELETE ON public.forum_votes
FOR EACH ROW EXECUTE FUNCTION public.update_vote_counts();
