-- =============================================================================
-- Migration 006: Superuser Hierarchy
-- =============================================================================
-- Implements:
-- 1. SUPERUSER role - god-like permissions
-- 2. is_initial_superuser flag - marks the founder (cannot be deleted)
-- 3. Initial superuser can only transfer their status (self-transfer only)
-- 4. Superusers can promote/demote other superusers (but not initial)
-- 5. Admins cannot touch superusers
-- =============================================================================

-- Add SUPERUSER to the user_role enum
ALTER TYPE user_role ADD VALUE IF NOT EXISTS 'SUPERUSER';

-- Add is_initial_superuser column to users table
-- This marks the very first user who gets god-like, non-removable status
ALTER TABLE users ADD COLUMN IF NOT EXISTS is_initial_superuser BOOLEAN DEFAULT false;

-- Add is_protected column to prevent deletion of critical users
ALTER TABLE users ADD COLUMN IF NOT EXISTS is_protected BOOLEAN DEFAULT false;

-- Create index for quick lookup of initial superuser
CREATE INDEX IF NOT EXISTS idx_users_initial_superuser ON users(is_initial_superuser) WHERE is_initial_superuser = true;

-- Create superuser_transfers table to track initial superuser transfers
-- This is an audit trail for when the initial superuser status is transferred
CREATE TABLE IF NOT EXISTS superuser_transfers (
    id SERIAL PRIMARY KEY,
    from_user_id INTEGER NOT NULL REFERENCES users(id),
    to_user_id INTEGER NOT NULL REFERENCES users(id),
    transferred_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    reason TEXT,
    -- Constraint: from_user must have been initial superuser
    CONSTRAINT valid_transfer CHECK (from_user_id != to_user_id)
);

-- Create index on superuser_transfers
CREATE INDEX IF NOT EXISTS idx_superuser_transfers_from ON superuser_transfers(from_user_id);
CREATE INDEX IF NOT EXISTS idx_superuser_transfers_to ON superuser_transfers(to_user_id);

-- Create trigger to ensure only one initial superuser exists at a time
CREATE OR REPLACE FUNCTION ensure_single_initial_superuser()
RETURNS TRIGGER AS $$
BEGIN
    IF NEW.is_initial_superuser = true THEN
        -- Check if there's already an initial superuser (other than this user)
        IF EXISTS (
            SELECT 1 FROM users
            WHERE is_initial_superuser = true
            AND id != NEW.id
        ) THEN
            RAISE EXCEPTION 'Only one initial superuser can exist at a time. Transfer must be explicit.';
        END IF;
    END IF;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER check_initial_superuser
    BEFORE INSERT OR UPDATE ON users
    FOR EACH ROW
    EXECUTE FUNCTION ensure_single_initial_superuser();

-- Create trigger to prevent deletion of initial superuser
CREATE OR REPLACE FUNCTION prevent_initial_superuser_deletion()
RETURNS TRIGGER AS $$
BEGIN
    IF OLD.is_initial_superuser = true THEN
        RAISE EXCEPTION 'Cannot delete the initial superuser. Transfer ownership first.';
    END IF;
    IF OLD.is_protected = true THEN
        RAISE EXCEPTION 'Cannot delete a protected user.';
    END IF;
    RETURN OLD;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER prevent_delete_initial_superuser
    BEFORE DELETE ON users
    FOR EACH ROW
    EXECUTE FUNCTION prevent_initial_superuser_deletion();

-- Create trigger to prevent removal of SUPERUSER role from initial superuser
CREATE OR REPLACE FUNCTION prevent_initial_superuser_role_removal()
RETURNS TRIGGER AS $$
DECLARE
    is_initial BOOLEAN;
BEGIN
    -- Check if the user being demoted is the initial superuser
    SELECT is_initial_superuser INTO is_initial FROM users WHERE id = OLD.user_id;

    IF is_initial = true AND OLD.role = 'SUPERUSER' THEN
        RAISE EXCEPTION 'Cannot remove SUPERUSER role from the initial superuser. Transfer ownership first.';
    END IF;

    RETURN OLD;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER prevent_initial_superuser_demotion
    BEFORE DELETE ON user_roles
    FOR EACH ROW
    EXECUTE FUNCTION prevent_initial_superuser_role_removal();

-- Create function to transfer initial superuser status
-- This MUST be called by the current initial superuser
CREATE OR REPLACE FUNCTION transfer_initial_superuser(
    current_su_id INTEGER,
    new_su_id INTEGER,
    transfer_reason TEXT DEFAULT NULL
)
RETURNS BOOLEAN AS $$
DECLARE
    is_current_initial BOOLEAN;
    new_user_exists BOOLEAN;
BEGIN
    -- Verify current user is the initial superuser
    SELECT is_initial_superuser INTO is_current_initial
    FROM users WHERE id = current_su_id;

    IF is_current_initial IS NULL OR is_current_initial = false THEN
        RAISE EXCEPTION 'Only the current initial superuser can transfer this status';
    END IF;

    -- Verify new user exists
    SELECT EXISTS(SELECT 1 FROM users WHERE id = new_su_id) INTO new_user_exists;
    IF new_user_exists = false THEN
        RAISE EXCEPTION 'Target user does not exist';
    END IF;

    -- Cannot transfer to self
    IF current_su_id = new_su_id THEN
        RAISE EXCEPTION 'Cannot transfer to yourself';
    END IF;

    -- Begin transfer
    -- 1. Remove initial_superuser flag from current user
    UPDATE users SET is_initial_superuser = false WHERE id = current_su_id;

    -- 2. Set initial_superuser flag on new user
    UPDATE users SET is_initial_superuser = true, is_protected = true WHERE id = new_su_id;

    -- 3. Ensure new user has SUPERUSER role
    INSERT INTO user_roles (user_id, role, created_at)
    VALUES (new_su_id, 'SUPERUSER', NOW())
    ON CONFLICT (user_id, role) DO NOTHING;

    -- 4. Record the transfer
    INSERT INTO superuser_transfers (from_user_id, to_user_id, reason)
    VALUES (current_su_id, new_su_id, transfer_reason);

    RETURN true;
END;
$$ LANGUAGE plpgsql;

-- Comment explaining the hierarchy
COMMENT ON COLUMN users.is_initial_superuser IS
'Marks the founding superuser. Cannot be deleted, can only transfer status to another user via self-initiated transfer.';

COMMENT ON COLUMN users.is_protected IS
'Protected users cannot be deleted. Initial superuser is always protected.';

COMMENT ON TABLE superuser_transfers IS
'Audit trail for initial superuser ownership transfers. Only the initial superuser can initiate a transfer.';
