-- ============================================================================
-- Bug Reporting System
-- ============================================================================
-- Access rules:
--   ALL authenticated users can INSERT (submit bug reports)
--   Only ADMIN and SUPER_ADMIN can SELECT, UPDATE (view/manage)
--   SALES_USER and DEVELOPER cannot view bug_reports after submission
-- ============================================================================

CREATE TABLE IF NOT EXISTS bug_reports (
    id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
    reported_by UUID NOT NULL REFERENCES users(id),
    title VARCHAR(255) NOT NULL,
    description TEXT NOT NULL,
    severity VARCHAR(20) NOT NULL DEFAULT 'medium'
        CHECK (severity IN ('low', 'medium', 'high', 'critical')),
    page_url TEXT,
    screenshot_url TEXT,
    status VARCHAR(20) NOT NULL DEFAULT 'open'
        CHECK (status IN ('open', 'in_progress', 'resolved', 'closed')),
    assigned_to UUID REFERENCES users(id),
    resolution_notes TEXT,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS idx_bug_reports_reported_by ON bug_reports(reported_by);
CREATE INDEX IF NOT EXISTS idx_bug_reports_status ON bug_reports(status);
CREATE INDEX IF NOT EXISTS idx_bug_reports_severity ON bug_reports(severity);
CREATE INDEX IF NOT EXISTS idx_bug_reports_assigned ON bug_reports(assigned_to);
CREATE INDEX IF NOT EXISTS idx_bug_reports_created ON bug_reports(created_at DESC);

-- RLS: Allow INSERT for all authenticated users
--      Allow SELECT/UPDATE only for ADMIN and SUPER_ADMIN
ALTER TABLE bug_reports ENABLE ROW LEVEL SECURITY;

DROP POLICY IF EXISTS bug_reports_insert ON bug_reports;
CREATE POLICY bug_reports_insert ON bug_reports
    FOR INSERT
    WITH CHECK (
        current_user_id() IS NOT NULL
        AND reported_by = current_user_id()
    );

DROP POLICY IF EXISTS bug_reports_select ON bug_reports;
CREATE POLICY bug_reports_select ON bug_reports
    FOR SELECT
    USING (
        current_user_hierarchy_level() IS NOT NULL
        AND current_user_hierarchy_level() <= 2
    );

DROP POLICY IF EXISTS bug_reports_update ON bug_reports;
CREATE POLICY bug_reports_update ON bug_reports
    FOR UPDATE
    USING (
        current_user_hierarchy_level() IS NOT NULL
        AND current_user_hierarchy_level() <= 2
    );

-- Audit trigger for bug report actions
CREATE OR REPLACE FUNCTION audit_bug_report_action()
RETURNS TRIGGER AS $$
BEGIN
    IF TG_OP = 'INSERT' THEN
        INSERT INTO audit_logs (table_name, record_id, action, new_data, changed_by)
        VALUES (
            'bug_reports',
            NEW.id,
            'BUG_CREATED',
            jsonb_build_object(
                'title', NEW.title,
                'severity', NEW.severity,
                'page_url', NEW.page_url,
                'status', NEW.status
            ),
            NEW.reported_by
        );
    ELSIF TG_OP = 'UPDATE' THEN
        IF OLD.status IS DISTINCT FROM NEW.status THEN
            INSERT INTO audit_logs (table_name, record_id, action, new_data, changed_by)
            VALUES (
                'bug_reports',
                NEW.id,
                CASE NEW.status
                    WHEN 'resolved' THEN 'BUG_RESOLVED'
                    ELSE 'BUG_UPDATED'
                END,
                jsonb_build_object(
                    'old_status', OLD.status,
                    'new_status', NEW.status,
                    'assigned_to', NEW.assigned_to,
                    'resolution_notes', NEW.resolution_notes
                ),
                NULLIF(current_setting('app.current_user_id', true), '')
            );
        END IF;
        IF OLD.assigned_to IS DISTINCT FROM NEW.assigned_to AND NEW.assigned_to IS NOT NULL THEN
            INSERT INTO audit_logs (table_name, record_id, action, new_data, changed_by)
            VALUES (
                'bug_reports',
                NEW.id,
                'BUG_ASSIGNED',
                jsonb_build_object(
                    'assigned_to', NEW.assigned_to,
                    'previous_assignee', OLD.assigned_to,
                    'status', NEW.status
                ),
                NULLIF(current_setting('app.current_user_id', true), '')
            );
        END IF;
    END IF;
    RETURN COALESCE(NEW, OLD);
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;

DROP TRIGGER IF EXISTS trg_audit_bug_report ON bug_reports;
CREATE TRIGGER trg_audit_bug_report
    AFTER INSERT OR UPDATE ON bug_reports
    FOR EACH ROW
    EXECUTE FUNCTION audit_bug_report_action();

-- Widen audit action constraint to include bug report events
ALTER TABLE audit_logs DROP CONSTRAINT IF EXISTS chk_audit_action;
ALTER TABLE audit_logs ADD CONSTRAINT chk_audit_action
    CHECK (action::text = ANY (ARRAY[
        'CREATE', 'UPDATE', 'DELETE',
        'BUG_CREATED', 'BUG_UPDATED', 'BUG_ASSIGNED', 'BUG_RESOLVED',
        'LOGIN', 'LOGOUT'
    ]::text[]));

-- Prevent SALES_USER and DEVELOPER from reading bug_reports directly
-- via RLS bypass attempts (additional safety via trigger)
CREATE OR REPLACE FUNCTION prevent_bug_report_read_bypass()
RETURNS TRIGGER AS $$
DECLARE
    user_level INT;
BEGIN
    user_level := current_user_hierarchy_level();
    IF user_level IS NULL OR user_level > 2 THEN
        RAISE EXCEPTION 'ACCESS DENIED: Only ADMIN and SUPER_ADMIN can view bug reports.';
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
