import { Request, Response, NextFunction } from "express";
import { catchAsyncError } from "../../middlewares/catchAsyncError";
import ErrorHandler from "../../middlewares/error";
import database from "../../config/db";

// controller: get activity feed
export const getActivityFeed = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const account = (req as any).user;
  const { 
    feed_type = 'following',
    page = 1,
    limit = 20
  } = req.query;
  
  const validFeedTypes = ['following', 'public', 'profile'];
  
  if (!validFeedTypes.includes(feed_type as string)) {
    return next(new ErrorHandler("Invalid feed type.", 400));
  }
  
  // Use database function to generate feed
  const feedResult = await database.query(
    `SELECT * FROM generate_activity_feed($1, $2, $3, $4)`,
    [account.id, feed_type, Number(page), Number(limit)]
  );
  
  const feed = feedResult.rows[0]?.generate_activity_feed || {};
  
  res.status(200).json({
    success: true,
    data: feed,
  });
});

// controller: create activity
export const createActivity = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const account = (req as any).user;
  const {
    verb,
    title,
    summary,
    content,
    target_id,
    object_id,
    object_type,
    visibility = 'followers',
    tags,
    mentions
  } = req.body;
  
  // Validate required fields
  if (!verb) {
    return next(new ErrorHandler("Verb is required.", 400));
  }
  
  const validVerbs = [
    'followed',
    'unfollowed',
    'posted',
    'liked',
    'commented',
    'shared',
    'joined',
    'updated_profile',
    'added_project',
    'launched_product',
    'achieved_milestone',
    'hired',
    'funded',
    'partnered'
  ];
  
  if (!validVerbs.includes(verb)) {
    return next(new ErrorHandler("Invalid verb.", 400));
  }
  
  // Validate target if provided
  if (target_id) {
    const targetResult = await database.query(
      `SELECT * FROM accounts WHERE id = $1 AND is_active = true`,
      [target_id]
    );
    
    if (targetResult.rows.length === 0) {
      return next(new ErrorHandler("Target account not found.", 404));
    }
  }
  
  // Validate visibility
  const validVisibility = ['public', 'followers', 'private', 'custom'];
  if (!validVisibility.includes(visibility)) {
    return next(new ErrorHandler("Invalid visibility setting.", 400));
  }
  
  // Use database function to create activity
  const activityResult = await database.query(
    `SELECT * FROM create_activity(
      $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11
    ) as activity_id`,
    [
      account.id,
      verb,
      title,
      summary,
      content || {},
      target_id || null,
      object_id || null,
      object_type || null,
      visibility,
      tags || [],
      mentions || []
    ]
  );
  
  const activityId = activityResult.rows[0]?.activity_id;
  
  // Get the created activity
  const activityQuery = await database.query(
    `SELECT 
      a.*,
      act.username as actor_username,
      act.display_name as actor_display_name,
      act.avatar as actor_avatar,
      act.account_type as actor_account_type,
      tgt.username as target_username,
      tgt.display_name as target_display_name
    FROM activities a
    INNER JOIN accounts act ON a.actor_id = act.id
    LEFT JOIN accounts tgt ON a.target_id = tgt.id
    WHERE a.id = $1`,
    [activityId]
  );
  
  const activity = activityQuery.rows[0];
  
  res.status(201).json({
    success: true,
    message: "Activity created successfully.",
    data: {
      activity: {
        id: activity.id,
        verb: activity.verb,
        title: activity.title,
        summary: activity.summary,
        content: activity.content,
        visibility: activity.visibility,
        created_at: activity.created_at,
        actor: {
          id: activity.actor_id,
          username: activity.actor_username,
          display_name: activity.actor_display_name,
          avatar: activity.actor_avatar,
          account_type: activity.actor_account_type,
        },
        target: activity.target_id ? {
          id: activity.target_id,
          username: activity.target_username,
          display_name: activity.target_display_name,
        } : null,
        tags: activity.tags,
        mentions: activity.mentions,
      },
    },
  });
});

// controller: get profile activities
export const getProfileActivities = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const { account_id } = req.params;
  const { 
    verb,
    page = 1,
    limit = 20
  } = req.query;
  
  const offset = (Number(page) - 1) * Number(limit);
  
  // Validate account exists
  const accountResult = await database.query(
    `SELECT * FROM accounts WHERE id = $1 AND is_active = true`,
    [account_id]
  );
  
  if (accountResult.rows.length === 0) {
    return next(new ErrorHandler("Account not found.", 404));
  }
  
  const account = accountResult.rows[0];
  
  // Check privacy
  const currentUser = (req as any).user;
  const isOwner = currentUser && currentUser.id === account_id;
  let isFollowing = false;
  
  // Check if current user follows the account (for followers visibility)
  if (currentUser && !isOwner) {
    const followResult = await database.query(
      `SELECT 1 FROM follows 
       WHERE follower_id = $1 AND following_id = $2 AND status = 'accepted'`,
      [currentUser.id, account_id]
    );
    
    if (followResult.rows.length > 0) {
      isFollowing = true;
    }
  }
  
  // Build where conditions
  const whereConditions: string[] = ["actor_id = $1"];
  const values: any[] = [account_id];
  let paramCounter = 2;
  
  // Apply visibility filter
  if (isOwner) {
    // Owner can see all activities
    whereConditions.push(`visibility IN ('public', 'followers', 'private')`);
  } else if (isFollowing) {
    // Followers can see public and followers activities
    whereConditions.push(`visibility IN ('public', 'followers')`);
  } else {
    // Public can only see public activities
    whereConditions.push(`visibility = 'public'`);
  }
  
  if (verb) {
    whereConditions.push(`verb = $${paramCounter}`);
    values.push(verb);
    paramCounter++;
  }
  
  // Add condition for non-expired activities
  whereConditions.push(`(expires_at IS NULL OR expires_at > CURRENT_TIMESTAMP)`);
  
  // Get count
  const countQuery = `
    SELECT COUNT(*) as total 
    FROM activities 
    WHERE ${whereConditions.join(' AND ')}
  `;
  
  const countResult = await database.query(countQuery, values);
  const total = parseInt(countResult.rows[0]?.total || 0);
  
  // Get activities
  const activitiesQuery = `
    SELECT 
      a.*,
      act.username as actor_username,
      act.display_name as actor_display_name,
      act.avatar as actor_avatar,
      act.account_type as actor_account_type,
      tgt.username as target_username,
      tgt.display_name as target_display_name
    FROM activities a
    INNER JOIN accounts act ON a.actor_id = act.id
    LEFT JOIN accounts tgt ON a.target_id = tgt.id
    WHERE ${whereConditions.join(' AND ')}
    ORDER BY a.created_at DESC
    LIMIT $${paramCounter} OFFSET $${paramCounter + 1}
  `;
  
  values.push(Number(limit));
  values.push(offset);
  
  const activitiesResult = await database.query(activitiesQuery, values);
  
  const activities = activitiesResult.rows.map((activity: any) => ({
    id: activity.id,
    verb: activity.verb,
    title: activity.title,
    summary: activity.summary,
    content: activity.content,
    visibility: activity.visibility,
    created_at: activity.created_at,
    metrics: {
      likes: activity.likes_count,
      comments: activity.comments_count,
      shares: activity.shares_count,
      views: activity.views_count,
    },
    actor: {
      id: activity.actor_id,
      username: activity.actor_username,
      display_name: activity.actor_display_name,
      avatar: activity.actor_avatar,
      account_type: activity.actor_account_type,
    },
    target: activity.target_id ? {
      id: activity.target_id,
      username: activity.target_username,
      display_name: activity.target_display_name,
    } : null,
    tags: activity.tags,
    mentions: activity.mentions,
  }));
  
  res.status(200).json({
    success: true,
    data: {
      activities,
      account: {
        id: account.id,
        username: account.username,
        display_name: account.display_name,
        account_type: account.account_type,
      },
      pagination: {
        page: Number(page),
        limit: Number(limit),
        total,
        pages: Math.ceil(total / Number(limit)),
      },
    },
  });
});

// controller: delete activity
export const deleteActivity = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const account = (req as any).user;
  const { activity_id } = req.params;
  
  // Check if activity exists and belongs to user
  const activityResult = await database.query(
    `SELECT * FROM activities WHERE id = $1 AND actor_id = $2`,
    [activity_id, account.id]
  );
  
  if (activityResult.rows.length === 0) {
    return next(new ErrorHandler("Activity not found or you don't have permission to delete it.", 404));
  }
  
  // Delete activity
  await database.query(
    `DELETE FROM activities WHERE id = $1`,
    [activity_id]
  );
  
  res.status(200).json({
    success: true,
    message: "Activity deleted successfully.",
  });
});

// controller: update activity visibility
export const updateActivityVisibility = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const account = (req as any).user;
  const { activity_id } = req.params;
  const { visibility } = req.body;
  
  if (!visibility) {
    return next(new ErrorHandler("Visibility is required.", 400));
  }
  
  const validVisibility = ['public', 'followers', 'private', 'custom'];
  if (!validVisibility.includes(visibility)) {
    return next(new ErrorHandler("Invalid visibility setting.", 400));
  }
  
  // Check if activity exists and belongs to user
  const activityResult = await database.query(
    `SELECT * FROM activities WHERE id = $1 AND actor_id = $2`,
    [activity_id, account.id]
  );
  
  if (activityResult.rows.length === 0) {
    return next(new ErrorHandler("Activity not found or you don't have permission to update it.", 404));
  }
  
  // Update visibility
  const result = await database.query(
    `UPDATE activities 
     SET visibility = $1, updated_at = CURRENT_TIMESTAMP
     WHERE id = $2
     RETURNING *`,
    [visibility, activity_id]
  );
  
  const updatedActivity = result.rows[0];
  
  res.status(200).json({
    success: true,
    message: "Activity visibility updated.",
    data: {
      activity: {
        id: updatedActivity.id,
        verb: updatedActivity.verb,
        title: updatedActivity.title,
        visibility: updatedActivity.visibility,
        updated_at: updatedActivity.updated_at,
      },
    },
  });
});

// controller: get trending activities
export const getTrendingActivities = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const { 
    timeframe = 'day',
    limit = 10
  } = req.query;
  
  const validTimeframes = ['hour', 'day', 'week', 'month'];
  if (!validTimeframes.includes(timeframe as string)) {
    return next(new ErrorHandler("Invalid timeframe.", 400));
  }
  
  // Calculate time threshold
  let timeThreshold = '1 hour';
  switch (timeframe) {
    case 'hour':
      timeThreshold = '1 hour';
      break;
    case 'day':
      timeThreshold = '1 day';
      break;
    case 'week':
      timeThreshold = '7 days';
      break;
    case 'month':
      timeThreshold = '30 days';
      break;
  }
  
  // Get trending activities based on engagement
  const trendingQuery = `
    SELECT 
      a.*,
      act.username as actor_username,
      act.display_name as actor_display_name,
      act.avatar as actor_avatar,
      act.account_type as actor_account_type,
      -- Engagement score calculation
      (a.likes_count * 2 + a.comments_count * 3 + a.shares_count * 4 + a.views_count * 0.1) as engagement_score
    FROM activities a
    INNER JOIN accounts act ON a.actor_id = act.id
    WHERE a.visibility = 'public'
      AND a.created_at >= CURRENT_TIMESTAMP - INTERVAL '${timeThreshold}'
      AND (a.expires_at IS NULL OR a.expires_at > CURRENT_TIMESTAMP)
    ORDER BY engagement_score DESC, a.created_at DESC
    LIMIT $1
  `;
  
  const trendingResult = await database.query(trendingQuery, [Number(limit)]);
  
  const trendingActivities = trendingResult.rows.map((activity: any) => ({
    id: activity.id,
    verb: activity.verb,
    title: activity.title,
    summary: activity.summary,
    content: activity.content,
    created_at: activity.created_at,
    engagement_score: activity.engagement_score,
    metrics: {
      likes: activity.likes_count,
      comments: activity.comments_count,
      shares: activity.shares_count,
      views: activity.views_count,
    },
    actor: {
      id: activity.actor_id,
      username: activity.actor_username,
      display_name: activity.actor_display_name,
      avatar: activity.actor_avatar,
      account_type: activity.actor_account_type,
    },
  }));
  
  res.status(200).json({
    success: true,
    data: {
      trending: trendingActivities,
      timeframe,
      generated_at: new Date().toISOString(),
    },
  });
});