-- Migration 947: Advanced Moderation v0.11.2 (F411-F420)
-- Extends moderation system with queue, spam detection, strikes, and fingerprinting

-- F411: Enhance reports table with moderation queue features
ALTER TABLE reports ADD COLUMN IF NOT EXISTS category VARCHAR(50) DEFAULT 'other';
ALTER TABLE reports ADD COLUMN IF NOT EXISTS priority VARCHAR(20) DEFAULT 'normal';
ALTER TABLE reports ADD COLUMN IF NOT EXISTS resolution_note TEXT DEFAULT '';
ALTER TABLE reports ADD COLUMN IF NOT EXISTS resolution_action VARCHAR(50) DEFAULT '';
ALTER TABLE reports ADD COLUMN IF NOT EXISTS assigned_to UUID REFERENCES users(id);
ALTER TABLE reports ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW();

CREATE INDEX IF NOT EXISTS idx_reports_status_priority ON reports(status, priority);
CREATE INDEX IF NOT EXISTS idx_reports_assigned_to ON reports(assigned_to);
CREATE INDEX IF NOT EXISTS idx_reports_category ON reports(category);
CREATE INDEX IF NOT EXISTS idx_reports_created_at ON reports(created_at);

-- F413: Spam detection rules table (deterministic, no ML)
CREATE TABLE IF NOT EXISTS spam_rules (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    name VARCHAR(100) NOT NULL,
    description TEXT,
    rule_type VARCHAR(50) NOT NULL,           -- 'duplicate_content', 'excessive_links', 'bot_pattern', 'keyword'
    config JSONB NOT NULL DEFAULT '{}',        -- rule-specific configuration
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    severity VARCHAR(20) NOT NULL DEFAULT 'low', -- 'low', 'medium', 'high'
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

-- Seed default spam rules
INSERT INTO spam_rules (name, description, rule_type, config, severity) VALUES
    ('Duplicate Title', 'Flag tracks with identical titles uploaded within 24h', 'duplicate_content',
     '{"field": "title", "window_hours": 24, "min_duplicates": 3}', 'medium'),
    ('Excessive Links', 'Flag content with too many URLs', 'excessive_links',
     '{"max_links": 5, "fields": ["description", "bio"]}', 'low'),
    ('Rapid Upload', 'Flag accounts uploading too many tracks too fast', 'bot_pattern',
     '{"max_uploads_per_hour": 10, "max_uploads_per_day": 50}', 'high'),
    ('Rapid Comments', 'Flag accounts posting too many comments too fast', 'bot_pattern',
     '{"max_comments_per_minute": 5, "max_comments_per_hour": 60}', 'medium')
ON CONFLICT DO NOTHING;

-- F413: Spam detection log
CREATE TABLE IF NOT EXISTS spam_detections (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    rule_id UUID NOT NULL REFERENCES spam_rules(id),
    content_type VARCHAR(50) NOT NULL,        -- 'track', 'comment', 'profile'
    content_id UUID,
    details JSONB DEFAULT '{}',
    action_taken VARCHAR(50) DEFAULT 'flagged', -- 'flagged', 'auto_hidden', 'none'
    reviewed BOOLEAN DEFAULT FALSE,
    reviewed_by UUID REFERENCES users(id),
    reviewed_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_spam_detections_user_id ON spam_detections(user_id);
CREATE INDEX IF NOT EXISTS idx_spam_detections_reviewed ON spam_detections(reviewed) WHERE reviewed = FALSE;
CREATE INDEX IF NOT EXISTS idx_spam_detections_created_at ON spam_detections(created_at);

-- F414: Audio fingerprint results
CREATE TABLE IF NOT EXISTS audio_fingerprints (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    track_id UUID NOT NULL REFERENCES tracks(id) ON DELETE CASCADE,
    status VARCHAR(20) NOT NULL DEFAULT 'pending',  -- 'pending', 'clean', 'matched', 'error'
    matched_title VARCHAR(255),
    matched_artist VARCHAR(255),
    matched_album VARCHAR(255),
    confidence DECIMAL(5,2),                         -- match confidence 0-100
    external_id VARCHAR(255),                        -- ACRCloud reference
    raw_response JSONB DEFAULT '{}',
    reviewed BOOLEAN DEFAULT FALSE,
    reviewed_by UUID REFERENCES users(id),
    reviewed_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    CONSTRAINT uq_audio_fingerprint_track UNIQUE(track_id)
);

CREATE INDEX IF NOT EXISTS idx_audio_fingerprints_status ON audio_fingerprints(status);
CREATE INDEX IF NOT EXISTS idx_audio_fingerprints_track_id ON audio_fingerprints(track_id);

-- F415: Strike system
CREATE TABLE IF NOT EXISTS user_strikes (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    report_id UUID REFERENCES reports(id),
    reason TEXT NOT NULL,
    severity VARCHAR(20) NOT NULL DEFAULT 'warning', -- 'warning', 'minor', 'major'
    issued_by UUID NOT NULL REFERENCES users(id),
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    appealed BOOLEAN NOT NULL DEFAULT FALSE,
    appeal_text TEXT,
    appeal_resolved BOOLEAN NOT NULL DEFAULT FALSE,
    appeal_result VARCHAR(20),                       -- 'upheld', 'overturned'
    appeal_resolved_by UUID REFERENCES users(id),
    appeal_resolved_at TIMESTAMP WITH TIME ZONE,
    expires_at TIMESTAMP WITH TIME ZONE,             -- NULL = permanent
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_strikes_user_id ON user_strikes(user_id);
CREATE INDEX IF NOT EXISTS idx_strikes_active ON user_strikes(user_id, is_active) WHERE is_active = TRUE;
CREATE INDEX IF NOT EXISTS idx_strikes_appealed ON user_strikes(appealed) WHERE appealed = TRUE AND appeal_resolved = FALSE;

-- F415: User suspensions (triggered by strikes)
CREATE TABLE IF NOT EXISTS user_suspensions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    reason TEXT NOT NULL,
    suspended_by UUID NOT NULL REFERENCES users(id),
    suspended_until TIMESTAMP WITH TIME ZONE,        -- NULL = permanent
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    lifted_by UUID REFERENCES users(id),
    lifted_at TIMESTAMP WITH TIME ZONE,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_suspensions_user_id ON user_suspensions(user_id);
CREATE INDEX IF NOT EXISTS idx_suspensions_active ON user_suspensions(user_id) WHERE is_active = TRUE;

-- Moderation action log for audit trail
CREATE TABLE IF NOT EXISTS moderation_actions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    moderator_id UUID NOT NULL REFERENCES users(id),
    target_user_id UUID REFERENCES users(id),
    target_content_type VARCHAR(50),
    target_content_id UUID,
    action VARCHAR(50) NOT NULL,                     -- 'approve', 'reject', 'ban_temp', 'ban_perm', 'warn', 'strike', 'suspend', 'unsuspend'
    reason TEXT,
    metadata JSONB DEFAULT '{}',
    created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_mod_actions_moderator ON moderation_actions(moderator_id);
CREATE INDEX IF NOT EXISTS idx_mod_actions_target_user ON moderation_actions(target_user_id);
CREATE INDEX IF NOT EXISTS idx_mod_actions_created_at ON moderation_actions(created_at);
