-- Daemon Boyfriend Database Schema
-- Run with: psql -U postgres -d daemon_boyfriend -f schema.sql

-- Users table
CREATE TABLE IF NOT EXISTS users (
    id BIGSERIAL PRIMARY KEY,
    discord_id BIGINT NOT NULL UNIQUE,
    discord_username VARCHAR(255) NOT NULL,
    discord_display_name VARCHAR(255),
    custom_name VARCHAR(255),
    first_seen_at TIMESTAMPTZ DEFAULT NOW(),
    last_seen_at TIMESTAMPTZ DEFAULT NOW(),
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_users_discord_id ON users(discord_id);
CREATE INDEX IF NOT EXISTS ix_users_last_seen_at ON users(last_seen_at);

-- User preferences table
CREATE TABLE IF NOT EXISTS user_preferences (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    preference_key VARCHAR(100) NOT NULL,
    preference_value TEXT,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(user_id, preference_key)
);

CREATE INDEX IF NOT EXISTS ix_user_preferences_user_id ON user_preferences(user_id);

-- User facts table
CREATE TABLE IF NOT EXISTS user_facts (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    fact_type VARCHAR(50) NOT NULL,
    fact_content TEXT NOT NULL,
    confidence FLOAT DEFAULT 1.0,
    source VARCHAR(50) DEFAULT 'conversation',
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    learned_at TIMESTAMPTZ DEFAULT NOW(),
    last_referenced_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_user_facts_user_id ON user_facts(user_id);
CREATE INDEX IF NOT EXISTS ix_user_facts_fact_type ON user_facts(fact_type);
CREATE INDEX IF NOT EXISTS ix_user_facts_is_active ON user_facts(is_active);

-- Guilds table
CREATE TABLE IF NOT EXISTS guilds (
    id BIGSERIAL PRIMARY KEY,
    discord_id BIGINT NOT NULL UNIQUE,
    name VARCHAR(255) NOT NULL,
    joined_at TIMESTAMPTZ DEFAULT NOW(),
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    settings JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_guilds_discord_id ON guilds(discord_id);

-- Guild members table
CREATE TABLE IF NOT EXISTS guild_members (
    id BIGSERIAL PRIMARY KEY,
    guild_id BIGINT NOT NULL REFERENCES guilds(id) ON DELETE CASCADE,
    user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    guild_nickname VARCHAR(255),
    roles TEXT[],
    joined_guild_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(guild_id, user_id)
);

CREATE INDEX IF NOT EXISTS ix_guild_members_guild_id ON guild_members(guild_id);
CREATE INDEX IF NOT EXISTS ix_guild_members_user_id ON guild_members(user_id);

-- Conversations table
CREATE TABLE IF NOT EXISTS conversations (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    guild_id BIGINT,
    channel_id BIGINT,
    started_at TIMESTAMPTZ DEFAULT NOW(),
    last_message_at TIMESTAMPTZ DEFAULT NOW(),
    message_count INTEGER DEFAULT 0,
    is_active BOOLEAN NOT NULL DEFAULT TRUE,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_conversations_user_id ON conversations(user_id);
CREATE INDEX IF NOT EXISTS ix_conversations_channel_id ON conversations(channel_id);
CREATE INDEX IF NOT EXISTS ix_conversations_last_message_at ON conversations(last_message_at);
CREATE INDEX IF NOT EXISTS ix_conversations_is_active ON conversations(is_active);

-- Messages table
CREATE TABLE IF NOT EXISTS messages (
    id BIGSERIAL PRIMARY KEY,
    conversation_id BIGINT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
    user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    discord_message_id BIGINT,
    role VARCHAR(20) NOT NULL,
    content TEXT NOT NULL,
    has_images BOOLEAN NOT NULL DEFAULT FALSE,
    image_urls JSONB,
    token_count INTEGER,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_messages_conversation_id ON messages(conversation_id);
CREATE INDEX IF NOT EXISTS ix_messages_user_id ON messages(user_id);
CREATE INDEX IF NOT EXISTS ix_messages_created_at ON messages(created_at);

-- =====================================================
-- LIVING AI TABLES
-- =====================================================

-- Bot state table (mood, statistics, preferences per guild)
CREATE TABLE IF NOT EXISTS bot_states (
    id BIGSERIAL PRIMARY KEY,
    guild_id BIGINT UNIQUE,  -- NULL = global state
    mood_valence FLOAT DEFAULT 0.0,  -- -1.0 (sad) to 1.0 (happy)
    mood_arousal FLOAT DEFAULT 0.0,  -- -1.0 (calm) to 1.0 (excited)
    mood_updated_at TIMESTAMPTZ DEFAULT NOW(),
    total_messages_sent INTEGER DEFAULT 0,
    total_facts_learned INTEGER DEFAULT 0,
    total_users_known INTEGER DEFAULT 0,
    first_activated_at TIMESTAMPTZ DEFAULT NOW(),
    preferences JSONB DEFAULT '{}',
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_bot_states_guild_id ON bot_states(guild_id);

-- Bot opinions table (topic preferences)
CREATE TABLE IF NOT EXISTS bot_opinions (
    id BIGSERIAL PRIMARY KEY,
    guild_id BIGINT,  -- NULL = global opinion
    topic VARCHAR(255) NOT NULL,
    sentiment FLOAT DEFAULT 0.0,  -- -1.0 to 1.0
    interest_level FLOAT DEFAULT 0.5,  -- 0.0 to 1.0
    discussion_count INTEGER DEFAULT 0,
    reasoning TEXT,
    formed_at TIMESTAMPTZ DEFAULT NOW(),
    last_reinforced_at TIMESTAMPTZ DEFAULT NOW(),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(guild_id, topic)
);

CREATE INDEX IF NOT EXISTS ix_bot_opinions_guild_id ON bot_opinions(guild_id);
CREATE INDEX IF NOT EXISTS ix_bot_opinions_topic ON bot_opinions(topic);

-- User relationships table (relationship depth tracking)
CREATE TABLE IF NOT EXISTS user_relationships (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    guild_id BIGINT,  -- NULL = global relationship
    relationship_score FLOAT DEFAULT 10.0,  -- 0-100 scale
    total_interactions INTEGER DEFAULT 0,
    positive_interactions INTEGER DEFAULT 0,
    negative_interactions INTEGER DEFAULT 0,
    avg_message_length FLOAT DEFAULT 0.0,
    conversation_depth_avg FLOAT DEFAULT 0.0,
    shared_references JSONB DEFAULT '{}',
    first_interaction_at TIMESTAMPTZ DEFAULT NOW(),
    last_interaction_at TIMESTAMPTZ DEFAULT NOW(),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(user_id, guild_id)
);

CREATE INDEX IF NOT EXISTS ix_user_relationships_user_id ON user_relationships(user_id);
CREATE INDEX IF NOT EXISTS ix_user_relationships_guild_id ON user_relationships(guild_id);

-- User communication styles table (learned preferences)
CREATE TABLE IF NOT EXISTS user_communication_styles (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE UNIQUE,
    preferred_length VARCHAR(20) DEFAULT 'medium',  -- short/medium/long
    preferred_formality FLOAT DEFAULT 0.5,  -- 0=casual, 1=formal
    emoji_affinity FLOAT DEFAULT 0.5,  -- 0=none, 1=lots
    humor_affinity FLOAT DEFAULT 0.5,  -- 0=serious, 1=playful
    detail_preference FLOAT DEFAULT 0.5,  -- 0=concise, 1=detailed
    engagement_signals JSONB DEFAULT '{}',
    samples_collected INTEGER DEFAULT 0,
    confidence FLOAT DEFAULT 0.0,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_user_communication_styles_user_id ON user_communication_styles(user_id);

-- Scheduled events table (proactive behavior)
CREATE TABLE IF NOT EXISTS scheduled_events (
    id BIGSERIAL PRIMARY KEY,
    user_id BIGINT REFERENCES users(id) ON DELETE CASCADE,
    guild_id BIGINT,
    channel_id BIGINT,
    event_type VARCHAR(50) NOT NULL,  -- birthday, follow_up, reminder, etc.
    trigger_at TIMESTAMPTZ NOT NULL,
    title VARCHAR(255) NOT NULL,
    context JSONB DEFAULT '{}',
    is_recurring BOOLEAN DEFAULT FALSE,
    recurrence_rule VARCHAR(100),  -- yearly, monthly, etc.
    status VARCHAR(20) DEFAULT 'pending',  -- pending, triggered, cancelled
    triggered_at TIMESTAMPTZ,
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_scheduled_events_user_id ON scheduled_events(user_id);
CREATE INDEX IF NOT EXISTS ix_scheduled_events_trigger_at ON scheduled_events(trigger_at);
CREATE INDEX IF NOT EXISTS ix_scheduled_events_status ON scheduled_events(status);

-- Fact associations table (cross-user memory links)
CREATE TABLE IF NOT EXISTS fact_associations (
    id BIGSERIAL PRIMARY KEY,
    fact_id_1 BIGINT NOT NULL REFERENCES user_facts(id) ON DELETE CASCADE,
    fact_id_2 BIGINT NOT NULL REFERENCES user_facts(id) ON DELETE CASCADE,
    association_type VARCHAR(50) NOT NULL,  -- shared_interest, same_location, etc.
    strength FLOAT DEFAULT 0.5,
    discovered_at TIMESTAMPTZ DEFAULT NOW(),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    UNIQUE(fact_id_1, fact_id_2)
);

CREATE INDEX IF NOT EXISTS ix_fact_associations_fact_id_1 ON fact_associations(fact_id_1);
CREATE INDEX IF NOT EXISTS ix_fact_associations_fact_id_2 ON fact_associations(fact_id_2);

-- Mood history table (track mood changes over time)
CREATE TABLE IF NOT EXISTS mood_history (
    id BIGSERIAL PRIMARY KEY,
    guild_id BIGINT,
    valence FLOAT NOT NULL,
    arousal FLOAT NOT NULL,
    trigger_type VARCHAR(50) NOT NULL,  -- conversation, time_decay, event
    trigger_user_id BIGINT REFERENCES users(id) ON DELETE SET NULL,
    trigger_description TEXT,
    recorded_at TIMESTAMPTZ DEFAULT NOW(),
    created_at TIMESTAMPTZ DEFAULT NOW(),
    updated_at TIMESTAMPTZ DEFAULT NOW()
);

CREATE INDEX IF NOT EXISTS ix_mood_history_guild_id ON mood_history(guild_id);
CREATE INDEX IF NOT EXISTS ix_mood_history_recorded_at ON mood_history(recorded_at);

-- Add new columns to user_facts for enhanced memory
ALTER TABLE user_facts ADD COLUMN IF NOT EXISTS category VARCHAR(50);
ALTER TABLE user_facts ADD COLUMN IF NOT EXISTS importance FLOAT DEFAULT 0.5;
ALTER TABLE user_facts ADD COLUMN IF NOT EXISTS temporal_relevance VARCHAR(20);
ALTER TABLE user_facts ADD COLUMN IF NOT EXISTS expiry_date TIMESTAMPTZ;
ALTER TABLE user_facts ADD COLUMN IF NOT EXISTS extracted_from_message_id BIGINT;
ALTER TABLE user_facts ADD COLUMN IF NOT EXISTS extraction_context TEXT;
