-- V028: Create invite codes system for controlled registration
-- Purpose: Implement invite-based registration to control app access during beta/launch

-- Create invite codes table
CREATE TABLE IF NOT EXISTS invite_codes (
    id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
    code VARCHAR(20) NOT NULL UNIQUE,
    created_by VARCHAR(36) REFERENCES users(id),
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,

    -- Usage tracking
    uses INTEGER DEFAULT 0,
    max_uses INTEGER, -- NULL means unlimited

    -- Validity
    expires_at TIMESTAMP WITH TIME ZONE,
    is_active BOOLEAN DEFAULT true,

    -- Metadata
    description TEXT,
    metadata JSONB DEFAULT '{}',

    -- Constraints
    CONSTRAINT check_uses CHECK (uses >= 0),
    CONSTRAINT check_max_uses CHECK (max_uses IS NULL OR max_uses > 0),
    CONSTRAINT check_code_format CHECK (code ~ '^[A-Z0-9\-]+$')
);

-- Create index for fast code lookup
CREATE INDEX idx_invite_codes_code ON invite_codes(code) WHERE is_active = true;
CREATE INDEX idx_invite_codes_expires ON invite_codes(expires_at) WHERE expires_at IS NOT NULL;
CREATE INDEX idx_invite_codes_created_by ON invite_codes(created_by);

-- Create invite code usage tracking table
CREATE TABLE IF NOT EXISTS invite_code_uses (
    id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
    invite_code_id VARCHAR(36) REFERENCES invite_codes(id) ON DELETE CASCADE,
    used_by VARCHAR(36) REFERENCES users(id),
    used_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    user_email VARCHAR(255),
    user_ip VARCHAR(45),
    user_agent TEXT,

    -- Ensure one use per user
    UNIQUE(invite_code_id, used_by)
);

CREATE INDEX idx_invite_code_uses_code ON invite_code_uses(invite_code_id);
CREATE INDEX idx_invite_code_uses_user ON invite_code_uses(used_by);

-- Create admin users table for admin dashboard access
CREATE TABLE IF NOT EXISTS admin_users (
    id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
    email VARCHAR(255) NOT NULL UNIQUE,
    password_hash VARCHAR(255) NOT NULL,
    name VARCHAR(100),
    role VARCHAR(50) DEFAULT 'admin',

    -- Status
    is_active BOOLEAN DEFAULT true,
    last_login_at TIMESTAMP WITH TIME ZONE,

    -- Timestamps
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,

    -- Permissions (JSON array of permission strings)
    permissions JSONB DEFAULT '["users:read", "users:write", "invites:read", "invites:write", "analytics:read"]',

    -- Two-factor auth
    two_factor_secret VARCHAR(255),
    two_factor_enabled BOOLEAN DEFAULT false
);

CREATE INDEX idx_admin_users_email ON admin_users(email);

-- Create admin sessions table
CREATE TABLE IF NOT EXISTS admin_sessions (
    id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
    admin_user_id VARCHAR(36) REFERENCES admin_users(id) ON DELETE CASCADE,
    token_hash VARCHAR(255) NOT NULL UNIQUE,
    ip_address VARCHAR(45),
    user_agent TEXT,
    expires_at TIMESTAMP WITH TIME ZONE NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    last_activity_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_admin_sessions_token ON admin_sessions(token_hash);
CREATE INDEX idx_admin_sessions_admin ON admin_sessions(admin_user_id);
CREATE INDEX idx_admin_sessions_expires ON admin_sessions(expires_at);

-- Create audit log for admin actions
CREATE TABLE IF NOT EXISTS admin_audit_logs (
    id VARCHAR(36) PRIMARY KEY DEFAULT gen_random_uuid()::text,
    admin_user_id VARCHAR(36) REFERENCES admin_users(id),
    action VARCHAR(100) NOT NULL,
    entity_type VARCHAR(50),
    entity_id VARCHAR(36),
    details JSONB DEFAULT '{}',
    ip_address VARCHAR(45),
    user_agent TEXT,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_admin_audit_logs_admin ON admin_audit_logs(admin_user_id);
CREATE INDEX idx_admin_audit_logs_entity ON admin_audit_logs(entity_type, entity_id);
CREATE INDEX idx_admin_audit_logs_created ON admin_audit_logs(created_at);

-- Function to increment invite code uses
CREATE OR REPLACE FUNCTION increment_invite_code_uses()
RETURNS TRIGGER AS $$
BEGIN
    UPDATE invite_codes
    SET uses = uses + 1
    WHERE id = NEW.invite_code_id;
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Trigger to automatically increment uses
CREATE TRIGGER trigger_increment_invite_uses
AFTER INSERT ON invite_code_uses
FOR EACH ROW
EXECUTE FUNCTION increment_invite_code_uses();

-- Function to check if invite code is valid
CREATE OR REPLACE FUNCTION is_invite_code_valid(
    p_code VARCHAR(20)
) RETURNS TABLE (
    is_valid BOOLEAN,
    reason VARCHAR(100)
) AS $$
DECLARE
    v_invite RECORD;
BEGIN
    -- Find the invite code
    SELECT * INTO v_invite
    FROM invite_codes
    WHERE code = p_code AND is_active = true;

    -- Check if code exists
    IF NOT FOUND THEN
        RETURN QUERY SELECT false, 'Invalid invite code';
        RETURN;
    END IF;

    -- Check if expired
    IF v_invite.expires_at IS NOT NULL AND v_invite.expires_at < CURRENT_TIMESTAMP THEN
        RETURN QUERY SELECT false, 'Invite code has expired';
        RETURN;
    END IF;

    -- Check if max uses reached
    IF v_invite.max_uses IS NOT NULL AND v_invite.uses >= v_invite.max_uses THEN
        RETURN QUERY SELECT false, 'Invite code has reached maximum uses';
        RETURN;
    END IF;

    -- Code is valid
    RETURN QUERY SELECT true, 'Valid';
END;
$$ LANGUAGE plpgsql;

-- Insert default admin user (password: admin123 - CHANGE THIS!)
-- Password hash is for 'admin123' using bcrypt
INSERT INTO admin_users (email, password_hash, name, role)
VALUES (
    'admin@parentflowapp.com',
    '$2b$10$YourHashHere', -- Replace with actual bcrypt hash
    'System Administrator',
    'super_admin'
) ON CONFLICT (email) DO NOTHING;

-- Insert some sample invite codes for testing
INSERT INTO invite_codes (code, description, max_uses) VALUES
    ('BETA2024', 'Beta testing invite', 100),
    ('LAUNCH50', 'Launch promotion - 50% off', 50),
    ('FRIENDS', 'Friends and family', NULL)
ON CONFLICT (code) DO NOTHING;

-- Add invite_code_used column to users table to track which code was used
ALTER TABLE users ADD COLUMN IF NOT EXISTS invite_code_used VARCHAR(20);
ALTER TABLE users ADD COLUMN IF NOT EXISTS registered_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP;

-- Create index for analytics
CREATE INDEX IF NOT EXISTS idx_users_invite_code ON users(invite_code_used);
CREATE INDEX IF NOT EXISTS idx_users_registered_at ON users(registered_at);