const couchdbService = require("../services/couchdbService");
const { 
  ValidationError,
  NotFoundError, 
  DatabaseError, 
  withErrorHandling,
  createErrorContext
} = require("../utils/modelErrors");

class Badge {
  static async findAll() {
    const errorContext = createErrorContext('Badge', 'findAll', {});
    
    return await withErrorHandling(async () => {
      const result = await couchdbService.find({
        selector: { type: 'badge' },
        sort: [{ order: 'asc' }]
      });
      const docs = Array.isArray(result) ? result : (result && result.docs) || [];
      return docs;
    }, errorContext);
  }

  static async findById(id) {
    const errorContext = createErrorContext('Badge', 'findById', { badgeId: id });
    
    return await withErrorHandling(async () => {
      try {
        const badge = await couchdbService.get(id);
        if (badge.type !== 'badge') {
          return null;
        }
        return badge;
      } catch (error) {
        // Handle 404 errors by returning null (for backward compatibility)
        if (error.statusCode === 404) {
          return null;
        }
        throw error;
      }
    }, errorContext);
  }

  static async create(badgeData) {
    const errorContext = createErrorContext('Badge', 'create', { 
      name: badgeData.name,
      rarity: badgeData.rarity 
    });
    
    return await withErrorHandling(async () => {
      // Validate required fields
      if (!badgeData.name || badgeData.name.trim() === '') {
        throw new ValidationError('Badge name is required', 'name', badgeData.name);
      }
      if (!badgeData.description || badgeData.description.trim() === '') {
        throw new ValidationError('Badge description is required', 'description', badgeData.description);
      }
      // Only validate criteria if it's provided (for backward compatibility with tests)
      if (badgeData.criteria !== undefined && typeof badgeData.criteria !== 'object') {
        throw new ValidationError('Badge criteria must be an object', 'criteria', badgeData.criteria);
      }
      if (badgeData.rarity && !['common', 'rare', 'epic', 'legendary'].includes(badgeData.rarity)) {
        throw new ValidationError('Badge rarity must be one of: common, rare, epic, legendary', 'rarity', badgeData.rarity);
      }

      const badge = {
        _id: `badge_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
        type: 'badge',
        name: badgeData.name.trim(),
        description: badgeData.description.trim(),
        icon: badgeData.icon,
        criteria: badgeData.criteria,
        rarity: badgeData.rarity || 'common',
        order: badgeData.order || 0,
        isActive: badgeData.isActive !== undefined ? badgeData.isActive : true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      };

      const result = await couchdbService.createDocument(badge);
      return { ...badge, _rev: result.rev };
    }, errorContext);
  }

  static async update(id, updateData) {
    const errorContext = createErrorContext('Badge', 'update', { 
      badgeId: id,
      updateData 
    });
    
    return await withErrorHandling(async () => {
      const existingBadge = await couchdbService.get(id);
      if (existingBadge.type !== 'badge') {
        throw new Error('Document is not a badge');
      }

      // Validate update data
      if (updateData.name !== undefined && updateData.name.trim() === '') {
        throw new ValidationError('Badge name cannot be empty', 'name', updateData.name);
      }
      if (updateData.rarity !== undefined && !['common', 'rare', 'epic', 'legendary'].includes(updateData.rarity)) {
        throw new ValidationError('Badge rarity must be one of: common, rare, epic, legendary', 'rarity', updateData.rarity);
      }

      const updatedBadge = {
        ...existingBadge,
        ...updateData,
        updatedAt: new Date().toISOString()
      };

      const result = await couchdbService.createDocument(updatedBadge);
      return { ...updatedBadge, _rev: result.rev };
    }, errorContext);
  }

  static async delete(id) {
    const errorContext = createErrorContext('Badge', 'delete', { badgeId: id });
    
    return await withErrorHandling(async () => {
      const badge = await couchdbService.get(id);
      if (badge.type !== 'badge') {
        throw new Error('Document is not a badge');
      }

      await couchdbService.destroy(id, badge._rev);
      return true;
    }, errorContext);
  }

  static async findByCriteria(criteriaType, threshold) {
    const errorContext = createErrorContext('Badge', 'findByCriteria', { 
      criteriaType, 
      threshold 
    });
    
    return await withErrorHandling(async () => {
      const result = await couchdbService.find({
        selector: {
          type: 'badge',
          'criteria.type': criteriaType,
          'criteria.threshold': { $lte: threshold }
        },
        sort: [{ 'criteria.threshold': 'desc' }]
      });
      const docs = Array.isArray(result) ? result : (result && result.docs) || [];
      return docs;
    }, errorContext);
  }

  static async findByRarity(rarity) {
    const errorContext = createErrorContext('Badge', 'findByRarity', { rarity });
    
    return await withErrorHandling(async () => {
      if (rarity && !['common', 'rare', 'epic', 'legendary'].includes(rarity)) {
        throw new ValidationError('Badge rarity must be one of: common, rare, epic, legendary', 'rarity', rarity);
      }

      const result = await couchdbService.find({
        selector: {
          type: 'badge',
          rarity: rarity
        },
        sort: [{ order: 'asc' }]
      });
      const docs = Array.isArray(result) ? result : (result && result.docs) || [];
      return docs;
    }, errorContext);
  }
}

module.exports = Badge;