-- Migration 002: Messaging System
-- Creates tables for conversations, messages, participants, reactions, calls, and files

-- ============================================================================
-- CONVERSATIONS
-- ============================================================================

-- Ensure all required columns exist for index creation
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS type VARCHAR(20);
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS created_by VARCHAR;
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS gameforge_project_id VARCHAR;
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS is_archived BOOLEAN DEFAULT false;
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS created_at TIMESTAMP DEFAULT NOW();
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS updated_at TIMESTAMP DEFAULT NOW();
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS title VARCHAR(200);
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS description TEXT;
ALTER TABLE conversations ADD COLUMN IF NOT EXISTS avatar_url VARCHAR(500);

CREATE TABLE IF NOT EXISTS conversations (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  type VARCHAR(20) NOT NULL CHECK (type IN ('direct', 'group', 'channel')),
  title VARCHAR(200),
  description TEXT,
  avatar_url VARCHAR(500),
  created_by VARCHAR REFERENCES users(id) ON DELETE SET NULL,
  gameforge_project_id VARCHAR, -- For GameForge integration (future)
  is_archived BOOLEAN DEFAULT false,
  created_at TIMESTAMP DEFAULT NOW(),
  updated_at TIMESTAMP DEFAULT NOW()
);

-- Create index on type column
CREATE INDEX idx_conversations_type ON conversations(type);
-- Create index on creator column
CREATE INDEX idx_conversations_creator ON conversations(created_by);
-- Create index on project column
CREATE INDEX idx_conversations_project ON conversations(gameforge_project_id);
-- Create index on updated_at column
CREATE INDEX idx_conversations_updated ON conversations(updated_at DESC);

-- ============================================================================
-- CONVERSATION PARTICIPANTS
-- ============================================================================

-- Update conversation_participants to match actual types and remove reference to identities
CREATE TABLE IF NOT EXISTS conversation_participants (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
  user_id VARCHAR NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  identity_id VARCHAR,
  role VARCHAR(20) DEFAULT 'member' CHECK (role IN ('admin', 'moderator', 'member')),
  joined_at TIMESTAMP DEFAULT NOW(),
  last_read_at TIMESTAMP,
  notification_settings JSONB DEFAULT '{"enabled": true, "mentions_only": false}'::jsonb,
  UNIQUE(conversation_id, user_id)
);

-- Create index on conversation column
CREATE INDEX idx_participants_conversation ON conversation_participants(conversation_id);
-- Create index on user column
CREATE INDEX idx_participants_user ON conversation_participants(user_id);
-- Create index on identity column
CREATE INDEX idx_participants_identity ON conversation_participants(identity_id);

-- ============================================================================
-- MESSAGES
-- ============================================================================

CREATE TABLE IF NOT EXISTS messages (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  conversation_id UUID NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
  sender_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  sender_identity_id UUID REFERENCES identities(id) ON DELETE SET NULL,
  content_encrypted TEXT NOT NULL, -- Encrypted message content
  content_type VARCHAR(20) DEFAULT 'text' CHECK (content_type IN ('text', 'image', 'video', 'audio', 'file')),
  metadata JSONB, -- Attachments, mentions, reactions, etc.
  reply_to_id UUID REFERENCES messages(id) ON DELETE SET NULL,
  edited_at TIMESTAMP,
  deleted_at TIMESTAMP,
  created_at TIMESTAMP DEFAULT NOW()
);

-- Ensure reply_to_id column exists for index creation
ALTER TABLE messages ADD COLUMN IF NOT EXISTS reply_to_id UUID;

-- Create index on conversation and created_at columns
CREATE INDEX idx_messages_conversation ON messages(conversation_id, created_at DESC);
-- Create index on sender column
CREATE INDEX idx_messages_sender ON messages(sender_id);
-- Create index on reply_to column
CREATE INDEX idx_messages_reply_to ON messages(reply_to_id);
-- Create index on created_at column
CREATE INDEX idx_messages_created ON messages(created_at DESC);

-- ============================================================================
-- MESSAGE REACTIONS
-- ============================================================================

-- Update message_reactions to match actual types
CREATE TABLE IF NOT EXISTS message_reactions (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  message_id UUID NOT NULL REFERENCES messages(id) ON DELETE CASCADE,
  user_id VARCHAR NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  emoji VARCHAR(20) NOT NULL,
  created_at TIMESTAMP DEFAULT NOW(),
  UNIQUE(message_id, user_id, emoji)
);

-- Create index on message column
CREATE INDEX idx_reactions_message ON message_reactions(message_id);
-- Create index on user column
CREATE INDEX idx_reactions_user ON message_reactions(user_id);

-- ============================================================================
-- FILES
-- ============================================================================

CREATE TABLE IF NOT EXISTS files (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  uploader_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  conversation_id UUID REFERENCES conversations(id) ON DELETE SET NULL,
  filename VARCHAR(255) NOT NULL,
  original_filename VARCHAR(255) NOT NULL,
  mime_type VARCHAR(100) NOT NULL,
  size_bytes BIGINT NOT NULL,
  storage_url VARCHAR(500) NOT NULL, -- GCP Cloud Storage URL or Supabase Storage
  thumbnail_url VARCHAR(500), -- For images/videos
  encryption_key TEXT, -- If file is encrypted
  created_at TIMESTAMP DEFAULT NOW(),
  expires_at TIMESTAMP -- For temporary files
);

-- Ensure uploader_id column exists for index creation
ALTER TABLE files ADD COLUMN IF NOT EXISTS uploader_id VARCHAR;

-- Ensure conversation_id column exists for index creation
ALTER TABLE files ADD COLUMN IF NOT EXISTS conversation_id UUID;

-- Create index on uploader column
CREATE INDEX idx_files_uploader ON files(uploader_id);
-- Create index on conversation column
CREATE INDEX idx_files_conversation ON files(conversation_id);
-- Create index on created_at column
CREATE INDEX idx_files_created ON files(created_at DESC);

-- ============================================================================
-- CALLS
-- ============================================================================

-- Update calls to match actual types
CREATE TABLE IF NOT EXISTS calls (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  conversation_id UUID REFERENCES conversations(id) ON DELETE SET NULL,
  type VARCHAR(20) NOT NULL CHECK (type IN ('voice', 'video')),
  initiator_id VARCHAR NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  status VARCHAR(20) DEFAULT 'ringing' CHECK (status IN ('ringing', 'active', 'ended', 'missed', 'declined')),
  started_at TIMESTAMP,
  ended_at TIMESTAMP,
  duration_seconds INTEGER,
  created_at TIMESTAMP DEFAULT NOW()
);

-- Create index on conversation column
CREATE INDEX idx_calls_conversation ON calls(conversation_id);
-- Create index on initiator column
CREATE INDEX idx_calls_initiator ON calls(initiator_id);
-- Create index on status column
CREATE INDEX idx_calls_status ON calls(status);
-- Create index on created_at column
CREATE INDEX idx_calls_created ON calls(created_at DESC);

-- ============================================================================
-- CALL PARTICIPANTS
-- ============================================================================

-- Update call_participants to match actual types
CREATE TABLE IF NOT EXISTS call_participants (
  id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
  call_id UUID NOT NULL REFERENCES calls(id) ON DELETE CASCADE,
  user_id VARCHAR NOT NULL REFERENCES users(id) ON DELETE CASCADE,
  joined_at TIMESTAMP,
  left_at TIMESTAMP,
  media_state JSONB DEFAULT '{"audio": true, "video": false, "screen_share": false}'::jsonb,
  UNIQUE(call_id, user_id)
);

-- Create index on call column
CREATE INDEX idx_call_participants_call ON call_participants(call_id);
-- Create index on user column
CREATE INDEX idx_call_participants_user ON call_participants(user_id);

-- ============================================================================
-- FUNCTIONS AND TRIGGERS
-- ============================================================================

-- Function to update conversation updated_at timestamp when messages are added
CREATE OR REPLACE FUNCTION update_conversation_timestamp()
RETURNS TRIGGER AS $$
BEGIN
  UPDATE conversations
  SET updated_at = NOW()
  WHERE id = NEW.conversation_id;
  RETURN NEW;
END;
$$ LANGUAGE plpgsql;

-- Trigger to update conversation timestamp on new message
CREATE TRIGGER trigger_update_conversation_timestamp
AFTER INSERT ON messages
FOR EACH ROW
EXECUTE FUNCTION update_conversation_timestamp();

-- Function to automatically create direct conversation if it doesn't exist
CREATE OR REPLACE FUNCTION get_or_create_direct_conversation(user1_id UUID, user2_id UUID)
RETURNS UUID AS $$
DECLARE
  conv_id UUID;
BEGIN
  -- Try to find existing direct conversation between these users
  SELECT c.id INTO conv_id
  FROM conversations c
  WHERE c.type = 'direct'
    AND EXISTS (
      SELECT 1 FROM conversation_participants cp1
      WHERE cp1.conversation_id = c.id AND cp1.user_id = user1_id
    )
    AND EXISTS (
      SELECT 1 FROM conversation_participants cp2
      WHERE cp2.conversation_id = c.id AND cp2.user_id = user2_id
    );
  
  -- If not found, create new direct conversation
  IF conv_id IS NULL THEN
    INSERT INTO conversations (type, created_by)
    VALUES ('direct', user1_id)
    RETURNING id INTO conv_id;
    
    -- Add both participants
    INSERT INTO conversation_participants (conversation_id, user_id)
    VALUES (conv_id, user1_id), (conv_id, user2_id);
  END IF;
  
  RETURN conv_id;
END;
$$ LANGUAGE plpgsql;
