// src/routes/userRoutes.js
const express = require('express');
const db = require('../db');
const auth = require('../middleware/authMiddleware');
// === SECURITY HARDENING: FIELD-LEVEL ENCRYPTION ===
const { decryptPhoneNumber } = require('../utils/fieldEncryption');

// === SECURITY HARDENING: STEP-UP AUTH ===
const { requireRecentOtpOrReauth } = require('../middleware/stepUpAuth');

// === SECURITY HARDENING: RATE LIMITING ===
const {
  userRateLimitRead,
  userRateLimitWrite,
  userRateLimitSensitive,
} = require('../middleware/userRateLimit');

// === VALIDATION: USER ROUTES ===
const {
  validateUpdateProfileBody,
  validateDeviceIdParam,
  validateLogoutOthersBody,
} = require('../middleware/validation');

const router = express.Router();

// GET /users/me
// Rate limited: Read operation (100 requests per 15 minutes per user)
router.get('/me', auth, userRateLimitRead, async (req, res) => {
  try {
    // Get user basic information (with new schema fields)
    const { rows } = await db.query(
      `SELECT id, phone_number, name, user_type, roles, active_role, 
              rating_average, rating_count, subscription_plan_id, subscription_expires_at,
              created_at, last_login_at, avatar_url, language, timezone, country_code
       FROM users
       WHERE id = $1 AND deleted = FALSE`,
      [req.user.id]
    );

    if (rows.length === 0) {
      return res.status(404).json({ error: 'User not found' });
    }

    const user = rows[0];

    // === SECURITY HARDENING: FIELD-LEVEL ENCRYPTION ===
    // Decrypt phone number before returning to client
    if (user.phone_number) {
      user.phone_number = decryptPhoneNumber(user.phone_number);
    }

    // Get active devices count
    const deviceCountResult = await db.query(
      `SELECT COUNT(*) as count FROM user_devices WHERE user_id = $1 AND is_active = true`,
      [req.user.id]
    );
    const activeDevicesCount = parseInt(deviceCountResult.rows[0].count, 10);

    // Get user's saved locations (addresses) - with new schema fields
    const locationsResult = await db.query(
      `SELECT 
        id,
        country,
        state,
        district,
        city_village,
        pincode,
        lat,
        lng,
        location_type,
        is_saved_address,
        selected_location,
        source_type,
        source_confidence,
        created_at,
        updated_at
       FROM locations
       WHERE user_id = $1 AND is_saved_address = true AND deleted = FALSE
       ORDER BY updated_at DESC`,
      [req.user.id]
    );

    const locations = locationsResult.rows.map(loc => ({
      id: loc.id,
      country: loc.country,
      state: loc.state,
      district: loc.district,
      city_village: loc.city_village,
      pincode: loc.pincode,
      coordinates: loc.lat && loc.lng ? {
        latitude: parseFloat(loc.lat),
        longitude: parseFloat(loc.lng)
      } : null,
      location_type: loc.location_type,
      is_saved_address: loc.is_saved_address,
      selected_location: loc.selected_location || false,
      source_type: loc.source_type,
      source_confidence: loc.source_confidence,
      created_at: loc.created_at,
      updated_at: loc.updated_at
    }));

    // Get primary location (most recent saved address, or first if none)
    const primaryLocation = locations.length > 0 ? locations[0] : null;

    return res.json({
      id: user.id,
      phone_number: user.phone_number,
      name: user.name,
      user_type: user.user_type, // System role: 'user', 'admin', 'moderator'
      roles: user.roles || ['seller_buyer'], // Marketplace roles array
      active_role: user.active_role || 'seller_buyer', // Active marketplace role
      rating_average: user.rating_average || 0,
      rating_count: user.rating_count || 0,
      subscription_plan_id: user.subscription_plan_id,
      subscription_expires_at: user.subscription_expires_at,
      avatar_url: user.avatar_url,
      language: user.language,
      timezone: user.timezone,
      country_code: user.country_code || '+91',
      created_at: user.created_at,
      last_login_at: user.last_login_at,
      active_devices_count: activeDevicesCount,
      location: primaryLocation, // Primary/saved location for convenience
      locations: locations // All saved locations
    });
  } catch (err) {
    console.error('get me error', err);
    return res.status(500).json({ error: 'Internal server error' });
  }
});

// PUT /users/me
// Rate limited: Write operation (20 requests per 15 minutes per user)
// Validates: name (optional, max 100), user_type (optional enum: seller/buyer/service_provider)
router.put(
  '/me',
  auth,
  userRateLimitWrite,
  requireRecentOtpOrReauth,
  validateUpdateProfileBody,
  async (req, res) => {
  try {
    const { name, active_role } = req.body;

    if (!name) {
      return res.status(400).json({ error: 'name is required' });
    }

    // Build update query - active_role comes from validation middleware
    const updateFields = ['name = $1'];
    const updateValues = [name];
    let paramIndex = 2;

    if (active_role) {
      // active_role is already validated and mapped by validation middleware
      updateFields.push(`active_role = $${paramIndex}`);
      updateValues.push(active_role);
      paramIndex++;
      
      // Also update roles array to include this role if not already present
      updateFields.push(`roles = CASE WHEN $${paramIndex}::listing_role_enum = ANY(roles) THEN roles ELSE array_append(roles, $${paramIndex}::listing_role_enum) END`);
      updateValues.push(active_role);
      paramIndex++;
    }

    updateValues.push(req.user.id);

    const { rows } = await db.query(
      `
      UPDATE users
      SET ${updateFields.join(', ')}
      WHERE id = $${paramIndex} AND deleted = FALSE
      RETURNING id, phone_number, name, user_type, roles, active_role, rating_average, rating_count
      `,
      updateValues
    );

    if (rows.length === 0) {
      return res.status(404).json({ error: 'User not found' });
    }

    const updatedUser = rows[0];
    
    // === SECURITY HARDENING: FIELD-LEVEL ENCRYPTION ===
    // Decrypt phone number before returning to client
    if (updatedUser.phone_number) {
      updatedUser.phone_number = decryptPhoneNumber(updatedUser.phone_number);
    }

    return res.json(updatedUser);
  } catch (err) {
    console.error('update me error', err);
    // Log more details for debugging
    if (err.code) {
      console.error('Database error code:', err.code);
      console.error('Database error message:', err.message);
    }
    return res.status(500).json({ 
      error: 'Internal server error',
      // Include error details in development
      ...(process.env.NODE_ENV !== 'production' && { 
        details: err.message,
        code: err.code 
      })
    });
  }
  }
);

// GET /users/me/devices - List all active devices
// Rate limited: Read operation (100 requests per 15 minutes per user)
router.get('/me/devices', auth, userRateLimitRead, async (req, res) => {
  try {
    const { rows } = await db.query(
      `
      SELECT 
        device_identifier,
        device_platform,
        device_model,
        os_version,
        app_version,
        language_code,
        timezone,
        first_seen_at,
        last_seen_at,
        is_active
      FROM user_devices
      WHERE user_id = $1 AND is_active = true
      ORDER BY last_seen_at DESC
      `,
      [req.user.id]
    );

    return res.json({ devices: rows });
  } catch (err) {
    console.error('get devices error', err);
    return res.status(500).json({ error: 'Internal server error' });
  }
});

// DELETE /users/me/devices/:device_id - Revoke/logout a specific device
// Rate limited: Sensitive operation (10 requests per hour per user)
// Validates: device_id param (string, max 100 chars)
router.delete(
  '/me/devices/:device_id',
  auth,
  userRateLimitSensitive,
  requireRecentOtpOrReauth,
  validateDeviceIdParam,
  async (req, res) => {
  try {
    const { device_id } = req.params;

    if (!device_id) {
      return res.status(400).json({ error: 'device_id is required' });
    }

    // Mark device as inactive
    await db.query(
      `UPDATE user_devices SET is_active = false WHERE user_id = $1 AND device_identifier = $2`,
      [req.user.id, device_id]
    );

    // Revoke all refresh tokens for this device
    const { revokeRefreshToken } = require('../services/tokenService');
    await revokeRefreshToken(req.user.id, device_id);

    // Log the action
    try {
      await db.query(
        `INSERT INTO auth_audit (user_id, action, status, device_id, ip_address, user_agent, meta)
         VALUES ($1, 'device_revoked', 'success', $2, $3, $4, $5)`,
        [
          req.user.id,
          device_id,
          req.ip,
          req.headers['user-agent'],
          JSON.stringify({ revoked_by: 'user' }),
        ]
      );
    } catch (auditErr) {
      console.error('Failed to log device revocation', auditErr);
    }

    return res.json({ ok: true, message: 'Device logged out successfully' });
  } catch (err) {
    console.error('revoke device error', err);
    return res.status(500).json({ error: 'Internal server error' });
  }
  }
);

// POST /users/me/logout-all-other-devices - Logout all other devices (keep current)
// Rate limited: Sensitive operation (10 requests per hour per user)
// Validates: current_device_id (optional string, max 100 chars if provided)
router.post(
  '/me/logout-all-other-devices',
  auth,
  userRateLimitSensitive,
  requireRecentOtpOrReauth,
  validateLogoutOthersBody,
  async (req, res) => {
  try {
    // Get current device_id from refresh token if available, or from request
    // For now, we'll need device_id in request body or header
    const currentDeviceId = req.headers['x-device-id'] || req.body.current_device_id;

    if (!currentDeviceId) {
      return res.status(400).json({ error: 'current_device_id is required in header or body' });
    }

    // Mark all other devices as inactive
    const result = await db.query(
      `UPDATE user_devices 
       SET is_active = false 
       WHERE user_id = $1 AND device_identifier != $2 AND is_active = true
       RETURNING device_identifier`,
      [req.user.id, currentDeviceId]
    );

    const revokedDevices = result.rows.map((row) => row.device_identifier);

    // Revoke refresh tokens for all other devices
    const { revokeRefreshToken } = require('../services/tokenService');
    for (const deviceId of revokedDevices) {
      await revokeRefreshToken(req.user.id, deviceId);
    }

    // Log the action
    try {
      await db.query(
        `INSERT INTO auth_audit (user_id, action, status, device_id, ip_address, user_agent, meta)
         VALUES ($1, 'logout_all_other_devices', 'success', $2, $3, $4, $5)`,
        [
          req.user.id,
          currentDeviceId,
          req.ip,
          req.headers['user-agent'],
          JSON.stringify({
            revoked_devices_count: revokedDevices.length,
            revoked_devices: revokedDevices,
          }),
        ]
      );
    } catch (auditErr) {
      console.error('Failed to log logout all action', auditErr);
    }

    return res.json({
      ok: true,
      message: `Logged out ${revokedDevices.length} device(s)`,
      revoked_devices_count: revokedDevices.length,
    });
  } catch (err) {
    console.error('logout all other devices error', err);
    return res.status(500).json({ error: 'Internal server error' });
  }
  }
);

// POST /users/me/logout-all-devices - Logout from ALL devices (including current)
// === SECURITY HARDENING: GLOBAL LOGOUT ===
// Rate limited: Sensitive operation (10 requests per hour per user)
// Requires step-up authentication (recent OTP or high_assurance token)
// Logs HIGH_RISK security event for audit
router.post(
  '/me/logout-all-devices',
  auth,
  userRateLimitSensitive,
  requireRecentOtpOrReauth,
  async (req, res) => {
  try {
    const { logAuthEvent, RISK_LEVELS } = require('../services/auditLogger');
    const { revokeAllUserTokens } = require('../services/tokenService');

    // Revoke all refresh tokens and invalidate all access tokens
    const result = await revokeAllUserTokens(req.user.id);

    // Log HIGH_RISK security event for audit
    await logAuthEvent({
      userId: req.user.id,
      action: 'logout_all_devices',
      status: 'success',
      riskLevel: RISK_LEVELS.HIGH_RISK,
      deviceId: req.headers['x-device-id'] || null,
      ipAddress: req.ip || req.connection.remoteAddress || 'unknown',
      userAgent: req.headers['user-agent'],
      meta: {
        revoked_tokens_count: result.revokedTokensCount,
        new_token_version: result.newTokenVersion,
        reason: 'user_initiated_global_logout',
        message: 'User initiated logout from all devices - security breach suspected',
      },
    });

    return res.json({
      ok: true,
      message: 'Logged out from all devices successfully',
      revoked_tokens_count: result.revokedTokensCount,
    });
  } catch (err) {
    console.error('logout all devices error', err);
    return res.status(500).json({ error: 'Internal server error' });
  }
  }
);

// POST /users/me/locations - Save a new location
// Rate limited: Write operation (20 requests per 15 minutes per user)
router.post(
  '/me/locations',
  auth,
  userRateLimitWrite,
  async (req, res) => {
    try {
      const {
        location_type,
        country,
        state,
        district,
        city_village,
        pincode,
        lat,
        lng,
        is_saved_address = true,
        selected_location = false,
        source_type = 'manual',
        source_confidence = 'medium',
      } = req.body;

      // Validate required fields
      if (!location_type) {
        return res.status(400).json({ error: 'location_type is required' });
      }

      // Insert location
      const { rows } = await db.query(
        `INSERT INTO locations (
          user_id, location_type, country, state, district, city_village, pincode,
          lat, lng, is_saved_address, selected_location, source_type, source_confidence
        )
        VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
        RETURNING id, location_type, country, state, district, city_village, pincode,
                  lat, lng, is_saved_address, selected_location, source_type, source_confidence,
                  created_at, updated_at`,
        [
          req.user.id,
          location_type,
          country || null,
          state || null,
          district || null,
          city_village || null,
          pincode || null,
          lat || null,
          lng || null,
          is_saved_address,
          selected_location,
          source_type,
          source_confidence,
        ]
      );

      // If this is set as primary location, unset others
      if (selected_location) {
        await db.query(
          `UPDATE locations 
           SET selected_location = false 
           WHERE user_id = $1 AND id != $2`,
          [req.user.id, rows[0].id]
        );
      }

      const location = rows[0];
      return res.json({
        id: location.id,
        location_type: location.location_type,
        country: location.country,
        state: location.state,
        district: location.district,
        city_village: location.city_village,
        pincode: location.pincode,
        coordinates: location.lat && location.lng ? {
          latitude: parseFloat(location.lat),
          longitude: parseFloat(location.lng)
        } : null,
        is_saved_address: location.is_saved_address,
        selected_location: location.selected_location,
        source_type: location.source_type,
        source_confidence: location.source_confidence,
        created_at: location.created_at,
        updated_at: location.updated_at,
      });
    } catch (err) {
      console.error('Save location error:', err);
      return res.status(500).json({ error: 'Internal server error' });
    }
  }
);

module.exports = router;
