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

// Admin dashboard statistics
export const getAdminDashboard = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const admin = (req as any).user;
  
  // Verify admin permissions
  const isAdmin = await PermissionService.hasPermission(admin.id, 'system.manage_settings');
  if (!isAdmin) {
    return next(new ErrorHandler("Admin access required.", 403));
  }
  
  // Get statistics
  const [
    usersResult,
    companiesResult,
    activitiesResult,
    followsResult,
    rolesResult
  ] = await Promise.all([
    database.query(`SELECT COUNT(*) as count FROM accounts WHERE account_type = 'user' AND is_active = true`),
    database.query(`SELECT COUNT(*) as count FROM accounts WHERE account_type = 'company' AND is_active = true`),
    database.query(`SELECT COUNT(*) as count FROM activities WHERE created_at >= CURRENT_DATE - INTERVAL '7 days'`),
    database.query(`SELECT COUNT(*) as count FROM follows WHERE status = 'accepted'`),
    database.query(`SELECT COUNT(DISTINCT account_id) as count FROM role_assignments WHERE is_active = true`)
  ]);
  
  // Get recent activities
  const recentActivities = await database.query(
    `SELECT 
      a.*,
      acc.username as actor_username,
      acc.display_name as actor_display_name
    FROM activities a
    INNER JOIN accounts acc ON a.actor_id = acc.id
    ORDER BY a.created_at DESC
    LIMIT 10`
  );
  
  // Get system health
  const dbStatus = await database.query(`SELECT 1 as status`);
  
  res.status(200).json({
    success: true,
    data: {
      statistics: {
        total_users: parseInt(usersResult.rows[0]?.count || 0),
        total_companies: parseInt(companiesResult.rows[0]?.count || 0),
        recent_activities: parseInt(activitiesResult.rows[0]?.count || 0),
        total_follows: parseInt(followsResult.rows[0]?.count || 0),
        users_with_roles: parseInt(rolesResult.rows[0]?.count || 0),
      },
      recent_activities: recentActivities.rows,
      system_health: {
        database: dbStatus.rows.length > 0 ? 'healthy' : 'unhealthy',
        timestamp: new Date().toISOString(),
      },
      admin_user: {
        id: admin.id,
        username: admin.username,
        roles: admin.roles,
        permissions: admin.permissions,
      },
    },
  });
});

// Get all users (with pagination and filters)
export const getAllUsers = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const {
    account_type,
    is_active,
    is_verified,
    role,
    search,
    page = 1,
    limit = 20
  } = req.query;
  
  const offset = (Number(page) - 1) * Number(limit);
  
  let whereConditions: string[] = ["1=1"];
  const values: any[] = [];
  let paramCounter = 1;
  
  if (account_type) {
    whereConditions.push(`account_type = $${paramCounter}`);
    values.push(account_type);
    paramCounter++;
  }
  
  if (is_active !== undefined) {
    whereConditions.push(`is_active = $${paramCounter}`);
    values.push(is_active === 'true');
    paramCounter++;
  }
  
  if (is_verified !== undefined) {
    whereConditions.push(`is_email_verified = $${paramCounter}`);
    values.push(is_verified === 'true');
    paramCounter++;
  }
  
  if (search) {
    whereConditions.push(`(
      username ILIKE $${paramCounter} OR
      email ILIKE $${paramCounter} OR
      display_name ILIKE $${paramCounter} OR
      user_full_name ILIKE $${paramCounter} OR
      company_name ILIKE $${paramCounter}
    )`);
    values.push(`%${search}%`);
    paramCounter++;
  }
  
  if (role) {
    whereConditions.push(`EXISTS(
      SELECT 1 FROM role_assignments ra
      INNER JOIN roles r ON ra.role_id = r.id
      WHERE ra.account_id = accounts.id
        AND ra.is_active = true
        AND (ra.expires_at IS NULL OR ra.expires_at > CURRENT_TIMESTAMP)
        AND r.name = $${paramCounter}
    )`);
    values.push(role);
    paramCounter++;
  }
  
  const whereClause = whereConditions.join(' AND ');
  
  // Get count
  const countQuery = `
    SELECT COUNT(*) as total 
    FROM accounts 
    WHERE ${whereClause}
  `;
  
  const countResult = await database.query(countQuery, values);
  const total = parseInt(countResult.rows[0]?.total || 0);
  
  // Get users with roles
  const usersQuery = `
    SELECT 
      a.*,
      COALESCE(
        json_agg(
          DISTINCT jsonb_build_object(
            'role_name', r.name,
            'role_display_name', r.display_name,
            'is_primary', ra.is_primary
          )
        ) FILTER (WHERE ra.is_active = true AND (ra.expires_at IS NULL OR ra.expires_at > CURRENT_TIMESTAMP)),
        '[]'
      ) as roles
    FROM accounts a
    LEFT JOIN role_assignments ra ON a.id = ra.account_id AND ra.is_active = true
    LEFT JOIN roles r ON ra.role_id = r.id
    WHERE ${whereClause}
    GROUP BY a.id
    ORDER BY a.created_at DESC
    LIMIT $${paramCounter} OFFSET $${paramCounter + 1}
  `;
  
  values.push(Number(limit));
  values.push(offset);
  
  const usersResult = await database.query(usersQuery, values);
  
  const users = usersResult.rows.map((user: any) => {
    const { password_hash, reset_password_token, otp_code, ...sanitized } = user;
    return sanitized;
  });
  
  res.status(200).json({
    success: true,
    data: {
      users,
      pagination: {
        page: Number(page),
        limit: Number(limit),
        total,
        pages: Math.ceil(total / Number(limit)),
      },
    },
  });
});

// Update user status (suspend/activate)
export const updateUserStatus = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const admin = (req as any).user;
  const { user_id } = req.params;
  const { 
    account_status, 
    is_active, 
    suspension_reason, 
    suspension_ends_at 
  } = req.body;
  
  if (!user_id) {
    return next(new ErrorHandler("User ID is required.", 400));
  }
  
  // Check if user exists
  const userResult = await database.query(
    `SELECT * FROM accounts WHERE id = $1`,
    [user_id]
  );
  
  if (userResult.rows.length === 0) {
    return next(new ErrorHandler("User not found.", 404));
  }
  
  const user = userResult.rows[0];
  
  // Don't allow modifying super admins (except by other super admins)
  const isSuperAdmin = await PermissionService.hasRole(user.id, 'super_admin');
  const adminIsSuperAdmin = await PermissionService.hasRole(admin.id, 'super_admin');
  
  if (isSuperAdmin && !adminIsSuperAdmin) {
    return next(new ErrorHandler("Cannot modify super admin accounts.", 403));
  }
  
  // Prepare update
  const updates: any = {};
  if (account_status !== undefined) updates.account_status = account_status;
  if (is_active !== undefined) updates.is_active = is_active;
  if (suspension_reason !== undefined) updates.suspension_reason = suspension_reason;
  if (suspension_ends_at !== undefined) updates.suspension_ends_at = suspension_ends_at;
  
  if (Object.keys(updates).length === 0) {
    return next(new ErrorHandler("No updates provided.", 400));
  }
  
  // Build update query
  const setClauses: string[] = [];
  const values: any[] = [];
  let paramCounter = 1;
  
  Object.entries(updates).forEach(([key, value]) => {
    setClauses.push(`${key} = $${paramCounter}`);
    values.push(value);
    paramCounter++;
  });
  
  setClauses.push(`updated_at = CURRENT_TIMESTAMP`);
  
  const query = `
    UPDATE accounts 
    SET ${setClauses.join(', ')}
    WHERE id = $${paramCounter}
    RETURNING *
  `;
  
  values.push(user_id);
  
  const result = await database.query(query, values);
  const updatedUser = result.rows[0];
  
  // Log the action
  await database.query(
    `INSERT INTO permission_audit_log (
      action,
      target_account_id,
      performed_by,
      previous_value,
      new_value,
      reason
    ) VALUES ($1, $2, $3, $4, $5, $6)`,
    [
      'update_role', // Using update_role action for consistency
      user_id,
      admin.id,
      JSON.stringify(user),
      JSON.stringify(updatedUser),
      `Status updated by admin: ${admin.username}`
    ]
  );
  
  res.status(200).json({
    success: true,
    message: "User status updated successfully.",
    data: {
      user: {
        id: updatedUser.id,
        username: updatedUser.username,
        email: updatedUser.email,
        account_status: updatedUser.account_status,
        is_active: updatedUser.is_active,
        updated_at: updatedUser.updated_at,
      },
    },
  });
});

// Get system metrics and analytics
export const getSystemMetrics = catchAsyncError(async (req: Request, res: Response, next: NextFunction) => {
  const { timeframe = '7days' } = req.query;
  
  let interval = '7 days';
  switch (timeframe) {
    case '1day':
      interval = '1 day';
      break;
    case '7days':
      interval = '7 days';
      break;
    case '30days':
      interval = '30 days';
      break;
    case '90days':
      interval = '90 days';
      break;
  }
  
  // Get various metrics
  const [
    userGrowth,
    companyGrowth,
    activityGrowth,
    roleDistribution,
    topPermissions
  ] = await Promise.all([
    // User growth over time
    database.query(`
      SELECT 
        DATE(created_at) as date,
        COUNT(*) as new_users,
        SUM(COUNT(*)) OVER (ORDER BY DATE(created_at)) as total_users
      FROM accounts 
      WHERE created_at >= CURRENT_DATE - INTERVAL '${interval}'
        AND account_type = 'user'
      GROUP BY DATE(created_at)
      ORDER BY date
    `),
    
    // Company growth over time
    database.query(`
      SELECT 
        DATE(created_at) as date,
        COUNT(*) as new_companies,
        SUM(COUNT(*)) OVER (ORDER BY DATE(created_at)) as total_companies
      FROM accounts 
      WHERE created_at >= CURRENT_DATE - INTERVAL '${interval}'
        AND account_type = 'company'
      GROUP BY DATE(created_at)
      ORDER BY date
    `),
    
    // Activity statistics
    database.query(`
      SELECT 
        verb,
        COUNT(*) as count,
        COUNT(*) * 100.0 / SUM(COUNT(*)) OVER () as percentage
      FROM activities
      WHERE created_at >= CURRENT_DATE - INTERVAL '${interval}'
      GROUP BY verb
      ORDER BY count DESC
      LIMIT 10
    `),
    
    // Role distribution
    database.query(`
      SELECT 
        r.name as role_name,
        r.display_name,
        COUNT(DISTINCT ra.account_id) as user_count
      FROM role_assignments ra
      INNER JOIN roles r ON ra.role_id = r.id
      WHERE ra.is_active = true
        AND (ra.expires_at IS NULL OR ra.expires_at > CURRENT_TIMESTAMP)
      GROUP BY r.id, r.name, r.display_name
      ORDER BY user_count DESC
    `),
    
    // Most used permissions
    database.query(`
      SELECT 
        p.name as permission_name,
        p.display_name,
        COUNT(DISTINCT rp.role_id) as role_count
      FROM role_permissions rp
      INNER JOIN permissions p ON rp.permission_id = p.id
      WHERE rp.is_allowed = true
      GROUP BY p.id, p.name, p.display_name
      ORDER BY role_count DESC
      LIMIT 10
    `)
  ]);
  
  res.status(200).json({
    success: true,
    data: {
      timeframe,
      user_growth: userGrowth.rows,
      company_growth: companyGrowth.rows,
      activity_stats: activityGrowth.rows,
      role_distribution: roleDistribution.rows,
      top_permissions: topPermissions.rows,
      generated_at: new Date().toISOString(),
    },
  });
});