const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const User = require('../../models/User');
const Street = require('../../models/Street');
const Task = require('../../models/Task');
const Post = require('../../models/Post');
const Event = require('../../models/Event');
const Reward = require('../../models/Reward');
const Report = require('../../models/Report');

/**
 * Create a test user and return user object with token
 */
async function createTestUser(overrides = {}) {
  const defaultUser = {
    name: 'Test User',
    email: 'test@example.com',
    password: 'password123',
  };

  const userData = { ...defaultUser, ...overrides };
  
  // Generate a test ID that matches MongoDB ObjectId pattern for validation
  const userId = '507f1f77bcf86cd7994390' + Math.floor(Math.random() * 10);

  // Create mock user object directly (bypass User.create to avoid mock issues)
  const user = {
    _id: userId,
    _rev: '1-abc',
    type: 'user',
    ...userData,
    password: '$2a$10$hashedpassword', // Mock hashed password
    isPremium: false,
    points: 0,
    adoptedStreets: [],
    completedTasks: [],
    posts: [],
    events: [],
    earnedBadges: [],
    stats: {
      streetsAdopted: 0,
      tasksCompleted: 0,
      postsCreated: 0,
      eventsParticipated: 0,
      badgesEarned: 0
    },
    createdAt: '2023-01-01T00:00:00.000Z',
    updatedAt: '2023-01-01T00:00:00.000Z'
  };

  const token = jwt.sign(
    { user: { id: user._id } },
    process.env.JWT_SECRET,
    { expiresIn: 3600 }
  );

  return { user, token };
}

/**
 * Create multiple test users
 */
async function createTestUsers(count = 2) {
  const users = [];
  for (let i = 0; i < count; i++) {
    const { user, token } = await createTestUser({
      name: `Test User ${i + 1}`,
      email: `test${i + 1}@example.com`,
    });
    users.push({ user, token });
  }
  return users;
}

/**
 * Create a test street
 */
async function createTestStreet(userId, overrides = {}) {
  const defaultStreet = {
    name: 'Test Street',
    location: {
      type: 'Point',
      coordinates: [-73.935242, 40.730610],
    },
    city: 'Test City',
    state: 'TS',
  };

  // Add adoptedBy if userId is provided
  if (userId) {
    defaultStreet.adoptedBy = {
      userId: userId,
      name: 'Test User',
      profilePicture: ''
    };
    defaultStreet.status = 'adopted';
  }

  // Generate a test ID that matches CouchDB ID pattern
  const streetId = '507f1f77bcf86cd7994390' + Math.floor(Math.random() * 10);

  // Apply overrides to defaultStreet
  const finalStreetData = { ...defaultStreet, ...overrides };
  
  const street = {
    _id: streetId,
    id: streetId, // Add id property for compatibility
    _rev: '1-abc',
    type: 'street',
    ...finalStreetData,
    status: finalStreetData.status || 'available',
    adoptedBy: finalStreetData.adoptedBy || null,
    createdAt: '2023-01-01T00:00:00.000Z',
    updatedAt: '2023-01-01T00:00:00.000Z'
  };
  
  return street;
}

/**
 * Create a test task
 */
async function createTestTask(userId, streetId, overrides = {}) {
  const streetData = {
    streetId: streetId,
    name: 'Test Street',
    location: {
      type: 'Point',
      coordinates: [-73.935242, 40.730610],
    }
  };

  const defaultTask = {
    street: streetData,
    description: 'Test task description',
    type: 'cleaning',
    status: 'pending',
  };

  // Add completedBy if userId is provided
  if (userId) {
    defaultTask.completedBy = {
      userId: userId,
      name: 'Test User',
      profilePicture: ''
    };
    defaultTask.status = 'completed';
  }

  // Generate a test ID that matches CouchDB ID pattern
  const taskId = '507f1f77bcf86cd7994390' + Math.floor(Math.random() * 10);

  const task = {
    _id: taskId,
    _rev: '1-abc',
    type: 'task',
    ...defaultTask,
    pointsAwarded: 10,
    createdAt: '2023-01-01T00:00:00.000Z',
    updatedAt: '2023-01-01T00:00:00.000Z'
  };
  
  return task;
}

/**
 * Create a test post
 */
async function createTestPost(userId, overrides = {}) {
  const defaultPost = {
    user: userId,
    content: 'Test post content',
    type: 'text',
  };

  // Generate a test ID that matches CouchDB ID pattern
  const postId = '507f1f77bcf86cd7994390' + Math.floor(Math.random() * 10);

  const post = {
    _id: postId,
    _rev: '1-abc',
    type: 'post',
    ...defaultPost,
    likes: [],
    comments: [],
    commentsCount: 0,
    createdAt: '2023-01-01T00:00:00.000Z',
    updatedAt: '2023-01-01T00:00:00.000Z'
  };
  
  return post;
}

/**
 * Create a test event
 */
async function createTestEvent(userId, overrides = {}) {
  const defaultEvent = {
    title: 'Test Event',
    description: 'Test event description',
    date: new Date(Date.now() + 86400000).toISOString(), // Tomorrow
    location: 'Test Location',
  };

  // Generate a test ID that matches validator pattern
  const eventId = `event_${Math.random().toString(36).substr(2, 9)}`;

  const event = {
    _id: eventId,
    id: eventId, // Add id property for compatibility
    _rev: '1-abc',
    type: 'event',
    ...defaultEvent,
    participants: [],
    participantsCount: 0,
    status: 'upcoming',
    createdAt: '2023-01-01T00:00:00.000Z',
    updatedAt: '2023-01-01T00:00:00.000Z'
  };
  
  // Add participant if userId is provided
  if (userId) {
    event.participants.push({
      userId: userId,
      name: 'Test User',
      profilePicture: '',
      joinedAt: new Date().toISOString()
    });
    event.participantsCount = 1;
  }
  
  return event;
}

/**
 * Create a test reward
 */
async function createTestReward(overrides = {}) {
  const defaultReward = {
    name: 'Test Reward',
    description: 'Test reward description',
    cost: 100,
  };

  // Handle legacy field name mapping
  const rewardData = { ...defaultReward, ...overrides };
  if (rewardData.pointsCost && !rewardData.cost) {
    rewardData.cost = rewardData.pointsCost;
    delete rewardData.pointsCost;
  }

  // Generate a test ID that matches validator pattern
  const rewardId = `reward_${Math.random().toString(36).substr(2, 9)}`;

  const reward = {
    _id: rewardId,
    _rev: '1-abc',
    type: 'reward',
    ...rewardData,
    isActive: true,
    isPremium: rewardData.isPremium || false,
    createdAt: '2023-01-01T00:00:00.000Z',
    updatedAt: '2023-01-01T00:00:00.000Z'
  };
  
  return reward;
}

/**
 * Create a test report
 */
async function createTestReport(userId, streetId, overrides = {}) {
  const defaultReport = {
    street: streetId,
    reporter: userId,
    type: 'pothole',
    description: 'Test report description',
    status: 'pending',
  };

  // Generate a test ID that matches validator pattern
  const reportId = `report_${Math.random().toString(36).substr(2, 9)}`;

  const report = {
    _id: reportId,
    _rev: '1-abc',
    type: 'report',
    ...defaultReport,
    createdAt: '2023-01-01T00:00:00.000Z',
    updatedAt: '2023-01-01T00:00:00.000Z'
  };
  
  return report;
}

/**
 * Clean up all test data
 */
async function cleanupDatabase() {
  const couchdbService = require('../../services/couchdbService');
  await couchdbService.initialize();
  
  // Delete all documents by type
  const types = ['user', 'street', 'task', 'post', 'event', 'reward', 'report', 'badge', 'user_badge', 'point_transaction'];
  
  for (const type of types) {
    try {
      const docs = await couchdbService.findByType(type);
      for (const doc of docs) {
        await couchdbService.deleteDocument(doc._id, doc._rev);
      }
    } catch (error) {
      console.error(`Error cleaning up ${type}s:`, error.message);
    }
  }
}

module.exports = {
  createTestUser,
  createTestUsers,
  createTestStreet,
  createTestTask,
  createTestPost,
  createTestEvent,
  createTestReward,
  createTestReport,
  cleanupDatabase,
};
