#!/usr/bin/env node

// Setup module path to include backend node_modules
const path = require('path');
const backendPath = path.join(__dirname, '..', 'backend');
process.env.NODE_PATH = path.join(backendPath, 'node_modules') + ':' + (process.env.NODE_PATH || '');
require('module').Module._initPaths();

const Nano = require('nano');
require('dotenv').config({ path: path.join(backendPath, '.env') });

// Configuration
const COUCHDB_URL = process.env.COUCHDB_URL || 'http://localhost:5984';
const COUCHDB_USER = process.env.COUCHDB_USER || 'admin';
const COUCHDB_PASSWORD = process.env.COUCHDB_PASSWORD || 'admin';
const COUCHDB_DB_NAME = process.env.COUCHDB_DB_NAME || 'adopt-a-street';

class CouchDBSetup {
  constructor() {
    this.nano = Nano({
      url: COUCHDB_URL,
      auth: { username: COUCHDB_USER, password: COUCHDB_PASSWORD }
    });
  }

  async initialize() {
    console.log('🚀 Initializing CouchDB setup...');
    
    try {
      // Test connection
      await this.nano.info();
      console.log('✅ Connected to CouchDB');
    } catch (error) {
      console.error('❌ Failed to connect to CouchDB:', error.message);
      process.exit(1);
    }
  }

  async createDatabase() {
    console.log(`📦 Creating database: ${COUCHDB_DB_NAME}`);
    
    try {
      await this.nano.db.create(COUCHDB_DB_NAME);
      console.log('✅ Database created successfully');
    } catch (error) {
      if (error.statusCode === 412) {
        console.log('ℹ️  Database already exists');
      } else {
        console.error('❌ Failed to create database:', error.message);
        throw error;
      }
    }
  }

  async createIndexes() {
    console.log('🔍 Creating indexes...');
    
    const db = this.nano.use(COUCHDB_DB_NAME);
    
    // Create design document with indexes
    const designDoc = {
      _id: '_design/adopt-a-street',
      views: {
        users_by_email: {
          map: "function(doc) { if (doc.type === 'user') { emit(doc.email, doc); } }"
        },
        streets_by_location: {
          map: "function(doc) { if (doc.type === 'street') { emit(doc.location, doc); } }"
        },
        by_user: {
          map: "function(doc) { if (doc.user && doc.user.userId) { emit(doc.user.userId, doc); } }"
        },
        users_by_points: {
          map: "function(doc) { if (doc.type === 'user') { emit(doc.points, doc); } }"
        },
        posts_by_date: {
          map: "function(doc) { if (doc.type === 'post') { emit(doc.createdAt, doc); } }"
        },
        streets_by_status: {
          map: "function(doc) { if (doc.type === 'street') { emit(doc.status, doc); } }"
        },
        events_by_date_status: {
          map: "function(doc) { if (doc.type === 'event') { emit([doc.date, doc.status], doc); } }"
        },
        comments_by_post: {
          map: "function(doc) { if (doc.type === 'comment' && doc.post && doc.post.postId) { emit(doc.post.postId, doc); } }"
        },
        transactions_by_user_date: {
          map: "function(doc) { if (doc.type === 'point_transaction' && doc.user && doc.user.userId) { emit([doc.user.userId, doc.createdAt], doc); } }"
        }
      },
      indexes: {
        users_by_email: {
          index: {
            fields: ["type", "email"]
          },
          name: "user-by-email",
          type: "json"
        },
        streets_by_location: {
          index: {
            fields: ["type", "location"]
          },
          name: "streets-by-location",
          type: "json"
        },
        by_user: {
          index: {
            fields: ["type", "user.userId"]
          },
          name: "by-user",
          type: "json"
        },
        users_by_points: {
          index: {
            fields: ["type", "points"]
          },
          name: "users-by-points",
          type: "json"
        },
        posts_by_date: {
          index: {
            fields: ["type", "createdAt"]
          },
          name: "posts-by-date",
          type: "json"
        },
        streets_by_status: {
          index: {
            fields: ["type", "status"]
          },
          name: "streets-by-status",
          type: "json"
        },
        events_by_date_status: {
          index: {
            fields: ["type", "date", "status"]
          },
          name: "events-by-date-status",
          type: "json"
        },
        comments_by_post: {
          index: {
            fields: ["type", "post.postId"]
          },
          name: "comments-by-post",
          type: "json"
        },
        transactions_by_user_date: {
          index: {
            fields: ["type", "user.userId", "createdAt"]
          },
          name: "transactions-by-user-date",
          type: "json"
        }
      },
      language: "javascript"
    };

    try {
      await db.insert(designDoc);
      console.log('✅ Design document and indexes created successfully');
    } catch (error) {
      if (error.statusCode === 409) {
        // Document already exists, update it
        const existing = await db.get('_design/adopt-a-street');
        designDoc._rev = existing._rev;
        await db.insert(designDoc);
        console.log('✅ Design document and indexes updated successfully');
      } else {
        console.error('❌ Failed to create indexes:', error.message);
        throw error;
      }
    }
  }

  async createSecurityDocument() {
    console.log('🔒 Setting up security document...');
    
    const db = this.nano.use(COUCHDB_DB_NAME);
    
    const securityDoc = {
      admins: {
        names: [COUCHDB_USER],
        roles: []
      },
      members: {
        names: [],
        roles: []
      }
    };

    try {
      await db.insert(securityDoc, '_security');
      console.log('✅ Security document created successfully');
    } catch (error) {
      console.warn('⚠️  Failed to create security document:', error.message);
    }
  }

  async seedBadges() {
    console.log('🏆 Seeding badges...');
    
    const db = this.nano.use(COUCHDB_DB_NAME);
    
    // Check if badges already exist
    try {
      const existingBadges = await db.find({
        selector: { type: 'badge' },
        limit: 1
      });
      
      if (existingBadges.docs.length > 0) {
        console.log('ℹ️  Badges already exist, skipping seeding');
        return;
      }
    } catch (error) {
      // Continue with seeding
    }

    const badges = [
      // Street Adoption Badges
      {
        _id: 'badge_first_adoption',
        type: 'badge',
        name: 'First Adoption',
        description: 'Adopted your first street',
        icon: '🏡',
        criteria: { type: 'street_adoptions', threshold: 1 },
        rarity: 'common',
        order: 1,
        isActive: true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      },
      {
        _id: 'badge_street_adopter',
        type: 'badge',
        name: 'Street Adopter',
        description: 'Adopted 5 streets',
        icon: '🏘️',
        criteria: { type: 'street_adoptions', threshold: 5 },
        rarity: 'rare',
        order: 2,
        isActive: true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      },
      {
        _id: 'badge_neighborhood_champion',
        type: 'badge',
        name: 'Neighborhood Champion',
        description: 'Adopted 10 streets',
        icon: '🌆',
        criteria: { type: 'street_adoptions', threshold: 10 },
        rarity: 'epic',
        order: 3,
        isActive: true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      },
      {
        _id: 'badge_city_guardian',
        type: 'badge',
        name: 'City Guardian',
        description: 'Adopted 25 streets',
        icon: '🏙️',
        criteria: { type: 'street_adoptions', threshold: 25 },
        rarity: 'legendary',
        order: 4,
        isActive: true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      },
      // Task Completion Badges
      {
        _id: 'badge_first_task',
        type: 'badge',
        name: 'First Task',
        description: 'Completed your first task',
        icon: '✅',
        criteria: { type: 'task_completions', threshold: 1 },
        rarity: 'common',
        order: 5,
        isActive: true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      },
      {
        _id: 'badge_task_master',
        type: 'badge',
        name: 'Task Master',
        description: 'Completed 10 tasks',
        icon: '🎯',
        criteria: { type: 'task_completions', threshold: 10 },
        rarity: 'rare',
        order: 6,
        isActive: true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      },
      {
        _id: 'badge_dedicated_worker',
        type: 'badge',
        name: 'Dedicated Worker',
        description: 'Completed 50 tasks',
        icon: '🛠️',
        criteria: { type: 'task_completions', threshold: 50 },
        rarity: 'epic',
        order: 7,
        isActive: true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      },
      {
        _id: 'badge_maintenance_legend',
        type: 'badge',
        name: 'Maintenance Legend',
        description: 'Completed 100 tasks',
        icon: '⚡',
        criteria: { type: 'task_completions', threshold: 100 },
        rarity: 'legendary',
        order: 8,
        isActive: true,
        createdAt: new Date().toISOString(),
        updatedAt: new Date().toISOString()
      }
    ];

    try {
      const results = await db.bulk({ docs: badges });
      const successCount = results.filter(r => !r.error).length;
      console.log(`✅ Successfully seeded ${successCount} badges`);
    } catch (error) {
      console.error('❌ Failed to seed badges:', error.message);
      throw error;
    }
  }

  async verifySetup() {
    console.log('🔍 Verifying setup...');
    
    const db = this.nano.use(COUCHDB_DB_NAME);
    
    try {
      // Check database info
      const info = await db.info();
      console.log(`✅ Database "${info.db_name}" is ready`);
      console.log(`   - Doc count: ${info.doc_count}`);
      console.log(`   - Update seq: ${info.update_seq}`);
      
      // Check indexes
      const designDoc = await db.get('_design/adopt-a-street');
      const indexCount = Object.keys(designDoc.indexes || {}).length;
      console.log(`✅ ${indexCount} indexes created`);
      
      // Check badges
      const badges = await db.find({
        selector: { type: 'badge' },
        fields: ['name']
      });
      console.log(`✅ ${badges.docs.length} badges available`);
      
    } catch (error) {
      console.error('❌ Setup verification failed:', error.message);
      throw error;
    }
  }

  async run() {
    try {
      await this.initialize();
      await this.createDatabase();
      await this.createIndexes();
      await this.createSecurityDocument();
      await this.seedBadges();
      await this.verifySetup();
      
      console.log('\n🎉 CouchDB setup completed successfully!');
      console.log(`\n📋 Connection Details:`);
      console.log(`   URL: ${COUCHDB_URL}`);
      console.log(`   Database: ${COUCHDB_DB_NAME}`);
      console.log(`   User: ${COUCHDB_USER}`);
      console.log(`\n🌐 Access CouchDB at: ${COUCHDB_URL}/_utils`);
      
    } catch (error) {
      console.error('\n❌ Setup failed:', error.message);
      process.exit(1);
    }
  }
}

// Run setup if called directly
if (require.main === module) {
  const setup = new CouchDBSetup();
  setup.run().catch(console.error);
}

module.exports = CouchDBSetup;