const db = require('../database/db');

class GameForgeIntegrationService {

  /**
   * Provision communication infrastructure for new GameForge project
   */
  async provisionProject(projectData) {
    const {
      projectId,
      name,
      ownerId,
      ownerIdentifier,
      teamMembers,
      settings
    } = projectData;

    // Generate project subdomain (slug-based)
    const slug = this.generateSlug(name);
    const domain = `${slug}@forge.aethex.dev`;

    // Create integration record
    const integrationResult = await db.query(
      `INSERT INTO gameforge_integrations 
       (project_id, domain, auto_provision_channels, channel_config)
       VALUES ($1, $2, $3, $4)
       RETURNING *`,
      [
        projectId,
        domain,
        settings.autoProvisionChannels !== false,
        JSON.stringify({
          defaultChannels: settings.defaultChannels || ['general', 'dev', 'art'],
          customChannels: settings.customChannels || []
        })
      ]
    );

    if (integrationResult.rows.length === 0) {
      throw new Error('Failed to create GameForge integration');
    }

    const integration = integrationResult.rows[0];

    // Create channels
    const channels = [];
    const allChannelNames = [
      ...(settings.defaultChannels || ['general', 'dev', 'art']),
      ...(settings.customChannels || [])
    ];

    for (const channelName of allChannelNames) {
      const channel = await this.createProjectChannel(
        integration.id,
        projectId,
        channelName,
        slug,
        ownerId,
        teamMembers
      );
      channels.push(channel);
    }

    // Log audit event
    await db.query(
      `INSERT INTO audit_logs (user_id, action, resource_type, resource_id, metadata)
       VALUES ($1, 'gameforge_project_provisioned', 'gameforge_integration', $2, $3)`,
      [
        ownerId,
        integration.id,
        JSON.stringify({ projectId, channelCount: channels.length })
      ]
    );

    return {
      projectId: projectId,
      domain: domain,
      channels: channels,
      createdAt: integration.created_at
    };
  }

  /**
   * Create a channel for GameForge project
   */
  async createProjectChannel(integrationId, projectId, channelName, projectSlug, ownerId, teamMembers) {
    // Determine permissions based on channel name
    const permissions = this.getChannelPermissions(channelName);

    // Create conversation
    const title = `${projectSlug} - ${channelName}`;
    const description = this.getChannelDescription(channelName);

    const conversationResult = await db.query(
      `INSERT INTO conversations
       (type, title, description, created_by, gameforge_project_id)
       VALUES ('group', $1, $2, $3, $4)
       RETURNING *`,
      [title, description, ownerId, projectId]
    );

    if (conversationResult.rows.length === 0) {
      throw new Error('Failed to create conversation for GameForge channel');
    }

    const conversation = conversationResult.rows[0];

    // Add team members based on permissions
    const eligibleMembers = this.filterMembersByPermissions(teamMembers, permissions);

    for (const member of eligibleMembers) {
      // Get member's primary identity
      const identityResult = await db.query(
        `SELECT id FROM identities WHERE user_id = $1 AND is_primary = true`,
        [member.userId]
      );

      if (identityResult.rows.length > 0) {
        await db.query(
          `INSERT INTO conversation_participants 
           (conversation_id, user_id, identity_id, role)
           VALUES ($1, $2, $3, $4)`,
          [
            conversation.id,
            member.userId,
            identityResult.rows[0].id,
            member.userId === ownerId ? 'admin' : 'member'
          ]
        );
      }
    }

    // Store channel metadata
    const identifier = `${channelName}@${projectSlug}.forge.aethex.dev`;
    
    await db.query(
      `UPDATE conversations 
       SET metadata = $2 
       WHERE id = $1`,
      [
        conversation.id,
        JSON.stringify({
          channelName: channelName,
          projectId: projectId,
          permissions: permissions,
          identifier: identifier
        })
      ]
    );

    return {
      id: conversation.id,
      name: channelName,
      identifier: identifier,
      description: description,
      permissions: permissions,
      participantCount: eligibleMembers.length
    };
  }

  /**
   * Update team members (add/remove/update roles)
   */
  async updateTeamMembers(projectId, action, members) {
    // Get integration
    const integrationResult = await db.query(
      `SELECT * FROM gameforge_integrations WHERE project_id = $1`,
      [projectId]
    );

    if (integrationResult.rows.length === 0) {
      throw new Error('GameForge integration not found');
    }

    const integration = integrationResult.rows[0];

    // Get all channels for this project
    const channelsResult = await db.query(
      `SELECT * FROM conversations WHERE gameforge_project_id = $1`,
      [projectId]
    );

    const channels = channelsResult.rows;
    const updated = [];

    for (const member of members) {
      const memberUpdate = {
        userId: member.userId,
        addedToChannels: [],
        removedFromChannels: []
      };

      if (action === 'add' || action === 'update_role') {
        // Get member's primary identity
        const identityResult = await db.query(
          `SELECT id FROM identities WHERE user_id = $1 AND is_primary = true`,
          [member.userId]
        );

        if (identityResult.rows.length === 0) {
          continue; // Skip if no identity found
        }

        const identityId = identityResult.rows[0].id;

        // Add to appropriate channels based on role
        for (const channel of channels) {
          const metadata = channel.metadata || {};
          const permissions = metadata.permissions || ['all'];

          // Check if member should have access
          if (this.hasChannelAccess(member.role, permissions)) {
            // Check if already a participant
            const existingResult = await db.query(
              `SELECT * FROM conversation_participants 
               WHERE conversation_id = $1 AND user_id = $2`,
              [channel.id, member.userId]
            );

            if (existingResult.rows.length === 0) {
              // Add as participant
              await db.query(
                `INSERT INTO conversation_participants 
                 (conversation_id, user_id, identity_id, role)
                 VALUES ($1, $2, $3, 'member')`,
                [channel.id, member.userId, identityId]
              );

              memberUpdate.addedToChannels.push(channel.id);
            }
          } else {
            // Should not have access - remove if exists
            const removed = await db.query(
              `DELETE FROM conversation_participants 
               WHERE conversation_id = $1 AND user_id = $2
               RETURNING conversation_id`,
              [channel.id, member.userId]
            );

            if (removed.rows.length > 0) {
              memberUpdate.removedFromChannels.push(channel.id);
            }
          }
        }
      } else if (action === 'remove') {
        // Remove from all project channels
        for (const channel of channels) {
          const removed = await db.query(
            `DELETE FROM conversation_participants 
             WHERE conversation_id = $1 AND user_id = $2
             RETURNING conversation_id`,
            [channel.id, member.userId]
          );

          if (removed.rows.length > 0) {
            memberUpdate.removedFromChannels.push(channel.id);
          }
        }
      }

      updated.push(memberUpdate);
    }

    return updated;
  }

  /**
   * Archive project channels
   */
  async archiveProject(projectId) {
    // Get all channels
    const channelsResult = await db.query(
      `SELECT id FROM conversations WHERE gameforge_project_id = $1`,
      [projectId]
    );

    const channelIds = channelsResult.rows.map(row => row.id);

    // Archive all conversations
    await db.query(
      `UPDATE conversations 
       SET is_archived = true 
       WHERE gameforge_project_id = $1`,
      [projectId]
    );

    return {
      archived: true,
      channels: channelIds
    };
  }

  /**
   * Send system notification to project channel
   */
  async sendNotification(projectId, channelName, notification) {
    // Get channel by name
    const channelResult = await db.query(
      `SELECT c.* FROM conversations c
       WHERE c.gameforge_project_id = $1
       AND c.metadata->>'channelName' = $2`,
      [projectId, channelName]
    );

    if (channelResult.rows.length === 0) {
      throw new Error(`Channel ${channelName} not found for project`);
    }

    const channel = channelResult.rows[0];

    // Create system message
    const messageContent = this.formatSystemNotification(notification);

    // Note: System messages are not encrypted
    const messageResult = await db.query(
      `INSERT INTO messages 
       (conversation_id, sender_id, content_encrypted, content_type, metadata)
       VALUES ($1, NULL, $2, 'system', $3)
       RETURNING *`,
      [
        channel.id,
        messageContent,
        JSON.stringify({
          type: notification.type,
          title: notification.title,
          metadata: notification.metadata,
          actions: notification.actions
        })
      ]
    );

    const message = messageResult.rows[0];

    // Broadcast via WebSocket (handled by socket server)
    // The socket server will pick this up from database trigger or pub/sub

    return {
      messageId: message.id,
      channelId: channel.id
    };
  }

  /**
   * Helper: Generate URL-safe slug from project name
   */
  generateSlug(name) {
    return name
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')
      .replace(/^-|-$/g, '')
      .substring(0, 50);
  }

  /**
   * Helper: Get permissions for channel type
   */
  getChannelPermissions(channelName) {
    const permissionMap = {
      'general': ['all'],
      'announcements': ['all'],
      'dev': ['owner', 'developer'],
      'art': ['owner', 'artist'],
      'design': ['owner', 'designer'],
      'testing': ['owner', 'tester', 'developer'],
      'playtesting': ['all']
    };

    return permissionMap[channelName] || ['all'];
  }

  /**
   * Helper: Get default description for channel
   */
  getChannelDescription(channelName) {
    const descriptions = {
      'general': 'General project discussion and updates',
      'announcements': 'Important project announcements',
      'dev': 'Development discussion and technical topics',
      'art': 'Art and visual design discussion',
      'design': 'Game design and mechanics discussion',
      'testing': 'Bug reports and quality assurance',
      'playtesting': 'Playtester feedback and discussion'
    };

    return descriptions[channelName] || `${channelName} channel`;
  }

  /**
   * Helper: Filter members by channel permissions
   */
  filterMembersByPermissions(teamMembers, permissions) {
    if (permissions.includes('all')) {
      return teamMembers;
    }

    return teamMembers.filter(member => 
      permissions.includes(member.role) || permissions.includes('owner')
    );
  }

  /**
   * Helper: Check if role has access to channel
   */
  hasChannelAccess(role, permissions) {
    return permissions.includes('all') || permissions.includes(role);
  }

  /**
   * Helper: Format system notification message
   */
  formatSystemNotification(notification) {
    let message = `🔔 **${notification.title}**\n\n${notification.message}`;

    if (notification.metadata) {
      message += '\n\n';
      for (const [key, value] of Object.entries(notification.metadata)) {
        message += `• ${key}: ${value}\n`;
      }
    }

    return message;
  }
}

module.exports = new GameForgeIntegrationService();
