-- 010_auth_and_users.sql
-- Core Authentication and User Identity Tables (Aligned with ORIGIN)

-- === USERS ===
CREATE TABLE public.users (
    -- Primary Key
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    
    -- Authentication
    email VARCHAR(255) NOT NULL,
    email_verified_at TIMESTAMPTZ,
    password_hash VARCHAR(255),
    
    -- Profile Basic
    username VARCHAR(30) NOT NULL,
    slug VARCHAR(255),
    first_name VARCHAR(100),
    last_name VARCHAR(100),
    display_name VARCHAR(100),
    
    -- Legacy Profile fields (kept for Go compatibility, prefer user_profiles)
    avatar TEXT,
    bio TEXT,
    location VARCHAR(100),
    birthdate TIMESTAMPTZ,
    gender VARCHAR(20),
    
    -- Role & Status
    role public.user_role NOT NULL DEFAULT 'user',
    is_active BOOLEAN NOT NULL DEFAULT true,
    is_verified BOOLEAN NOT NULL DEFAULT false,
    is_banned BOOLEAN NOT NULL DEFAULT false,
    is_admin BOOLEAN DEFAULT false, -- Legacy boolean, prefer role='admin'
    is_public BOOLEAN DEFAULT true, -- Legacy visibility
    
    -- Security
    token_version INTEGER NOT NULL DEFAULT 0,
    last_password_change_at TIMESTAMPTZ,
    
    -- Tracking
    last_login_at TIMESTAMPTZ,
    login_count INTEGER NOT NULL DEFAULT 0,
    last_login_ip INET,
    username_changed_at TIMESTAMPTZ,
    
    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at TIMESTAMPTZ,
    
    -- Constraints
    CONSTRAINT chk_users_email_format CHECK (email ~* '^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}$'),
    CONSTRAINT chk_users_username_format CHECK (username ~* '^[a-zA-Z0-9_]{3,30}$')
);

-- Indexes
CREATE UNIQUE INDEX idx_users_email ON public.users(email) WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX idx_users_username ON public.users(username) WHERE deleted_at IS NULL;
CREATE UNIQUE INDEX idx_users_slug ON public.users(slug) WHERE deleted_at IS NULL;
CREATE INDEX idx_users_role ON public.users(role);
CREATE INDEX idx_users_created_at_desc ON public.users(created_at DESC);
CREATE INDEX idx_users_deleted_at ON public.users(deleted_at) WHERE deleted_at IS NOT NULL;

-- === FEDERATED IDENTITIES (OAuth) ===
CREATE TABLE public.federated_identities (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
    
    -- Provider
    provider VARCHAR(50) NOT NULL,
    provider_user_id VARCHAR(255) NOT NULL, -- ORIGIN name
    provider_id TEXT, -- Legacy name (kept for compatibility if needed, else deprecate)
    
    -- OAuth Data
    access_token TEXT,
    refresh_token TEXT,
    token_expires_at TIMESTAMPTZ, -- ORIGIN name
    expires_at TIMESTAMPTZ, -- Legacy name
    
    -- Profile Data
    provider_email VARCHAR(255),
    provider_username VARCHAR(255),
    provider_avatar_url TEXT,
    provider_profile_data JSONB,
    
    -- Legacy fields
    email TEXT, -- Maps to provider_email
    display_name TEXT,
    avatar_url TEXT, -- Maps to provider_avatar_url
    
    -- Status
    is_primary BOOLEAN NOT NULL DEFAULT false,
    
    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    CONSTRAINT uq_federated_identities_provider_user UNIQUE (provider, provider_user_id)
);

CREATE INDEX idx_federated_identities_user_id ON public.federated_identities(user_id);
CREATE INDEX idx_federated_identities_provider ON public.federated_identities(provider);

-- === REFRESH TOKENS ===
CREATE TABLE public.refresh_tokens (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
    
    -- Token
    token VARCHAR(255) NOT NULL UNIQUE,
    token_hash VARCHAR(255) NOT NULL,
    
    -- Metadata
    device_name VARCHAR(255),
    device_type VARCHAR(50),
    user_agent TEXT,
    ip_address INET,
    
    -- Expiration
    expires_at TIMESTAMPTZ NOT NULL,
    last_used_at TIMESTAMPTZ,
    
    -- Status
    is_revoked BOOLEAN NOT NULL DEFAULT false,
    revoked_at TIMESTAMPTZ,
    revoked_reason VARCHAR(255),
    
    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    deleted_at TIMESTAMPTZ, -- Legacy soft delete

    CONSTRAINT chk_refresh_tokens_expires_future CHECK (expires_at > created_at)
);

CREATE INDEX idx_refresh_tokens_user_id ON public.refresh_tokens(user_id);
CREATE INDEX idx_refresh_tokens_token_hash ON public.refresh_tokens(token_hash);
CREATE INDEX idx_refresh_tokens_expires_at ON public.refresh_tokens(expires_at);
CREATE INDEX idx_refresh_tokens_is_revoked ON public.refresh_tokens(is_revoked) WHERE is_revoked = false;

-- === PASSWORD RESET TOKENS ===
CREATE TABLE public.password_reset_tokens (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
    
    -- Token
    token VARCHAR(255) NOT NULL UNIQUE,
    token_hash VARCHAR(255) NOT NULL,
    
    -- Status
    used BOOLEAN NOT NULL DEFAULT false,
    used_at TIMESTAMPTZ,
    expires_at TIMESTAMPTZ NOT NULL,
    
    -- Metadata
    ip_address INET,
    user_agent TEXT,
    
    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    CONSTRAINT chk_password_reset_expires CHECK (expires_at > created_at)
);

CREATE INDEX idx_password_reset_tokens_user_id ON public.password_reset_tokens(user_id);
CREATE INDEX idx_password_reset_tokens_token_hash ON public.password_reset_tokens(token_hash);
CREATE INDEX idx_password_reset_tokens_expires_at ON public.password_reset_tokens(expires_at);

-- === EMAIL VERIFICATION TOKENS ===
CREATE TABLE public.email_verification_tokens (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
    
    -- Token
    token VARCHAR(255) NOT NULL UNIQUE,
    token_hash VARCHAR(255) NOT NULL,
    
    -- Email
    email VARCHAR(255) NOT NULL,
    
    -- Status
    verified BOOLEAN NOT NULL DEFAULT false, -- Legacy used
    used BOOLEAN NOT NULL DEFAULT false, -- Legacy used
    verified_at TIMESTAMPTZ,
    expires_at TIMESTAMPTZ NOT NULL,
    
    -- Timestamps
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),

    CONSTRAINT chk_email_verification_expires CHECK (expires_at > created_at)
);

CREATE INDEX idx_email_verification_tokens_user_id ON public.email_verification_tokens(user_id);
CREATE INDEX idx_email_verification_tokens_token_hash ON public.email_verification_tokens(token_hash);
CREATE INDEX idx_email_verification_tokens_email ON public.email_verification_tokens(email);

-- === USER SESSIONS (Legacy/Auth) ===
CREATE TABLE public.user_sessions (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL REFERENCES public.users(id) ON DELETE CASCADE,
    session_token VARCHAR(255) NOT NULL UNIQUE,
    
    ip_address INET, -- Changed to INET per Origin style
    user_agent TEXT,
    
    is_active BOOLEAN DEFAULT true,
    last_activity TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    expires_at TIMESTAMPTZ NOT NULL,
    revoked_at TIMESTAMPTZ,
    
    created_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMPTZ DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_user_sessions_user_id ON public.user_sessions(user_id);
CREATE INDEX idx_user_sessions_expires_at ON public.user_sessions(expires_at);
CREATE INDEX idx_user_sessions_last_activity ON public.user_sessions(last_activity DESC);