const axios = require('axios');

class NocoDBService {
  constructor() {
    // Accept either full API URL or base URL
    const rawApiUrl = process.env.NOCODB_API_URL || process.env.NOCODB_URL;
    this.apiToken = process.env.NOCODB_API_TOKEN;
    this.projectId = process.env.NOCODB_PROJECT_ID;
    this.timeout = 10000;

    // Normalize base URL and API prefix to avoid double "/api/v1"
    let baseUrl = rawApiUrl || '';
    if (baseUrl.endsWith('/')) baseUrl = baseUrl.slice(0, -1);
    // If env provided includes /api/v1, strip it from base and keep prefix
    if (/\/api\/v1$/.test(baseUrl)) {
      baseUrl = baseUrl.replace(/\/api\/v1$/, '');
    }
    this.baseUrl = baseUrl || '';
    this.apiPrefix = '/api/v1';
    
    // Table mapping from environment variables
    this.tableIds = {
      representatives: process.env.NOCODB_TABLE_REPRESENTATIVES,
      emails: process.env.NOCODB_TABLE_EMAILS,
      postalCodes: process.env.NOCODB_TABLE_POSTAL_CODES,
      campaigns: process.env.NOCODB_TABLE_CAMPAIGNS,
      campaignEmails: process.env.NOCODB_TABLE_CAMPAIGN_EMAILS,
      users: process.env.NOCODB_TABLE_USERS,
      calls: process.env.NOCODB_TABLE_CALLS,
      representativeResponses: process.env.NOCODB_TABLE_REPRESENTATIVE_RESPONSES,
      responseUpvotes: process.env.NOCODB_TABLE_RESPONSE_UPVOTES
    };
    
    // Validate that all table IDs are set
    const missingTables = Object.entries(this.tableIds)
      .filter(([key, value]) => !value)
      .map(([key]) => key);
    
    if (missingTables.length > 0) {
      console.error('Missing NocoDB table IDs in environment variables:', missingTables);
      console.error('Please run the build-nocodb.sh script to set up the database tables.');
    }
    
    // Create axios instance with normalized base URL
    this.client = axios.create({
      baseURL: this.baseUrl,
      timeout: this.timeout,
      headers: {
        'xc-token': this.apiToken,
        'Content-Type': 'application/json'
      }
    });
    
    // Add response interceptor for error handling
    this.client.interceptors.response.use(
      response => response,
      error => {
        console.error('NocoDB API Error:', {
          message: error.message,
          url: error.config?.url,
          method: error.config?.method,
          status: error.response?.status,
          data: error.response?.data
        });
        throw error;
      }
    );
  }

  // Build table URL using table ID
  getTableUrl(tableId) {
    // Always prefix with single "/api/v1"
    return `${this.apiPrefix}/db/data/v1/${this.projectId}/${tableId}`;
  }

  // Get all records from a table
  async getAll(tableId, params = {}) {
    const url = this.getTableUrl(tableId);
    const response = await this.client.get(url, { params });
    return response.data;
  }

  // Create record
  async create(tableId, data) {
    try {
      // Clean the data to remove any null values and system fields that NocoDB manages
      const cleanData = Object.keys(data).reduce((clean, key) => {
        // Skip null/undefined values
        if (data[key] === null || data[key] === undefined) {
          return clean;
        }
        
        // Skip any potential ID or system fields that NocoDB manages automatically
        const systemFields = ['id', 'Id', 'ID', 'CreatedAt', 'UpdatedAt', 'created_at', 'updated_at'];
        if (systemFields.includes(key)) {
          console.log(`Skipping system field: ${key}`);
          return clean;
        }
        
        clean[key] = data[key];
        return clean;
      }, {});
      
      console.log(`Creating record in table ${tableId} with data:`, JSON.stringify(cleanData, null, 2));
      
      const url = this.getTableUrl(tableId);
      const response = await this.client.post(url, cleanData);
      console.log(`Record created successfully in table ${tableId}`);
      return response.data;
    } catch (error) {
      console.error(`Error creating record in table ${tableId}:`, error.message);
      if (error.response?.data) {
        console.error('Full error response:', JSON.stringify(error.response.data, null, 2));
      }
      throw error;
    }
  }

  // Update record
  async update(tableId, recordId, data) {
    try {
      // Clean the data to remove any null values which can cause NocoDB issues
      const cleanData = Object.keys(data).reduce((clean, key) => {
        if (data[key] !== null && data[key] !== undefined) {
          clean[key] = data[key];
        }
        return clean;
      }, {});
      
      const url = `${this.getTableUrl(tableId)}/${recordId}`;
      const response = await this.client.patch(url, cleanData);
      return response.data;
    } catch (error) {
      console.error('Error updating record:', error);
      throw error;
    }
  }



  async storeRepresentatives(postalCode, representatives) {
    try {
      const stored = [];
      console.log(`Attempting to store ${representatives.length} representatives for postal code ${postalCode}`);
      
      // First, clear any existing representatives for this postal code to avoid duplicates
      try {
        const existingQuery = await this.getAll(this.tableIds.representatives, {
          where: `(Postal Code,eq,${postalCode})`
        });
        
        if (existingQuery.list && existingQuery.list.length > 0) {
          console.log(`Found ${existingQuery.list.length} existing representatives for ${postalCode}, using cached data`);
          return { success: true, count: existingQuery.list.length, cached: true };
        }
      } catch (checkError) {
        console.log('Could not check for existing representatives:', checkError.message);
        // Continue anyway
      }
      
      // Store each representative, handling duplicates gracefully
      for (const rep of representatives) {
        const record = {
          'Postal Code': postalCode,
          'Name': rep.name || '',
          'Email': rep.email || '',
          'District Name': rep.district_name || '',
          'Elected Office': rep.elected_office || '',
          'Party Name': rep.party_name || '',
          'Representative Set Name': rep.representative_set_name || '',
          'Profile URL': rep.url || '',
          'Photo URL': rep.photo_url || '',
          'Offices': rep.offices ? JSON.stringify(rep.offices) : '[]',
          'Cached At': new Date().toISOString()
        };
        
        try {
          const result = await this.create(this.tableIds.representatives, record);
          stored.push(result);
          console.log(`Successfully stored representative: ${rep.name}`);
        } catch (createError) {
          // Handle any duplicate or constraint errors gracefully
          if (createError.response?.status === 400) {
            console.log(`Skipping representative ${rep.name} due to constraint: ${createError.response?.data?.message || createError.message}`);
            // Continue to next representative without failing
          } else {
            console.log(`Error storing representative ${rep.name}:`, createError.message);
            // For non-400 errors, we might want to continue or fail - let's continue for now
          }
        }
      }

      console.log(`Successfully stored ${stored.length} out of ${representatives.length} representatives for ${postalCode}`);
      return { success: true, count: stored.length };
      
    } catch (error) {
      // Catch-all error handler - never let this method throw
      console.log('Error in storeRepresentatives:', error.response?.data || error.message);
      return { success: false, error: error.message, count: 0 };
    }
  }

  async getRepresentativesByPostalCode(postalCode) {
    try {
      // Try to query with the most likely column name
      const response = await this.getAll(this.tableIds.representatives, {
        where: `(Postal Code,eq,${postalCode})`
      });
      
      const cachedRecords = response.list || [];
      
      // Transform NocoDB format back to API format
      const transformedRecords = cachedRecords.map(record => ({
        name: record['Name'],
        email: record['Email'],
        district_name: record['District Name'],
        elected_office: record['Elected Office'],
        party_name: record['Party Name'],
        representative_set_name: record['Representative Set Name'],
        url: record['Profile URL'],
        photo_url: record['Photo URL'],
        offices: record['Offices'] ? JSON.parse(record['Offices']) : []
      }));
      
      return transformedRecords;
    } catch (error) {
      // If we get a 502 or other server error, just return empty array
      if (error.response && (error.response.status === 502 || error.response.status >= 500)) {
        console.log('NocoDB server unavailable (502/5xx error), returning empty cache result');
        return [];
      }
      
      // For other errors like column not found, also return empty array
      console.log('NocoDB cache error, returning empty array:', error.response?.data?.msg || error.message);
      return [];
    }
  }

  async clearRepresentativesByPostalCode(postalCode) {
    try {
      // Get existing records
      const existing = await this.getRepresentativesByPostalCode(postalCode);
      
      // Delete each record using client
      for (const record of existing) {
        const url = `${this.getTableUrl(this.tableIds.representatives)}/${record.Id}`;
        await this.client.delete(url);
      }
      
      return { success: true, deleted: existing.length };
    } catch (error) {
      console.error('Error clearing representatives:', error);
      throw error;
    }
  }

  async logEmailSend(emailData) {
    try {
      const record = {
        'Recipient Email': emailData.recipientEmail,
        'Sender Name': emailData.senderName,
        'Sender Email': emailData.senderEmail,
        'Subject': emailData.subject,
        'Message': emailData.message || '',
        'Postal Code': emailData.postalCode,
        'Status': emailData.status,
        'Sent At': emailData.timestamp,
        'Sender IP': emailData.senderIP || null // Add IP tracking for rate limiting
      };

      await this.create(this.tableIds.emails, record);
      return { success: true };
    } catch (error) {
      console.error('Error logging email:', error);
      throw error;
    }
  }

  async logEmailPreview(previewData) {
    try {
      // Let NocoDB handle all ID generation - just provide the basic data
      const record = {
        'Recipient Email': previewData.recipientEmail,
        'Sender Name': previewData.senderName,
        'Sender Email': previewData.senderEmail,
        'Subject': previewData.subject,
        'Message': previewData.message || '',
        'Postal Code': previewData.postalCode,
        'Status': 'previewed',
        'Sent At': new Date().toISOString(), // Simple timestamp, let NocoDB handle uniqueness
        'Sender IP': previewData.senderIP || 'unknown'
      };

      console.log('Attempting to log email preview...');
      await this.create(this.tableIds.emails, record);
      console.log('Email preview logged successfully');
      return { success: true };
    } catch (error) {
      console.error('Error logging email preview:', error);
      
      // Check if it's a duplicate record error
      if (error.response && error.response.data && error.response.data.code === '23505') {
        console.warn('Duplicate constraint violation - this suggests NocoDB has hidden unique constraints');
        console.warn('Skipping preview log to avoid breaking the preview functionality');
        return { success: true, warning: 'Duplicate preview log skipped due to constraint' };
      }
      
      // Don't throw error - preview logging is optional and shouldn't break the preview
      console.warn('Preview logging failed but continuing with preview functionality');
      return { success: false, error: error.message };
    }
  }

  // Check if an email was recently sent to this recipient from this IP
  async checkRecentEmailSend(senderIP, recipientEmail, windowMinutes = 5) {
    try {
      const windowStart = new Date(Date.now() - (windowMinutes * 60 * 1000)).toISOString();
      
      const params = {
        where: `(Sender IP,eq,${senderIP})~and(Recipient Email,eq,${recipientEmail})~and(Sent At,gte,${windowStart})`,
        sort: '-CreatedAt',
        limit: 1
      };

      const response = await this.getAll(this.tableIds.emails, params);
      return response.list && response.list.length > 0 ? response.list[0] : null;
    } catch (error) {
      console.error('Error checking recent email send:', error);
      return null; // On error, allow the send (fallback to in-memory limiter)
    }
  }

  async getEmailLogs(filters = {}) {
    try {
      let whereClause = '';
      const conditions = [];
      
      if (filters.postalCode) {
        conditions.push(`(Postal Code,eq,${filters.postalCode})`);
      }
      if (filters.senderEmail) {
        conditions.push(`(sender_email,eq,${filters.senderEmail})`);
      }
      if (filters.status) {
        conditions.push(`(status,eq,${filters.status})`);
      }
      
      if (conditions.length > 0) {
        whereClause = `?where=${conditions.join('~and')}`;
      }

      const params = {};
      if (conditions.length > 0) {
        params.where = conditions.join('~and');
      }
      params.sort = '-CreatedAt';
      
      const response = await this.getAll(this.tableIds.emails, params);
      return response.list || [];
    } catch (error) {
      console.error('Error getting email logs:', error);
      return [];
    }
  }

  async storePostalCodeInfo(postalCodeData) {
    try {
      // Map fields to NocoDB column titles
      const mappedData = {
        'Postal Code': postalCodeData.postal_code,
        'City': postalCodeData.city,
        'Province': postalCodeData.province
      };
      const response = await this.create(this.tableIds.postalCodes, mappedData);
      return response;
    } catch (error) {
      // Don't throw error for postal code caching failures
      console.log('Postal code info storage failed:', error.message);
      return null;
    }
  }

  // Campaign management methods
  async getAllCampaigns() {
    try {
      const response = await this.getAll(this.tableIds.campaigns, {
        sort: '-CreatedAt',
        // Explicitly request all fields to ensure newly added columns are included
        fields: '*'
      });
      return response.list || [];
    } catch (error) {
      console.error('Get all campaigns failed:', error);
      throw error;
    }
  }

  async getCampaignById(id) {
    try {
      // Use direct record endpoint to avoid casing issues on Id column
      const url = `${this.getTableUrl(this.tableIds.campaigns)}/${id}`;
      const response = await this.client.get(url);
      return response.data || null;
    } catch (error) {
      console.error('Get campaign by ID failed:', error);
      throw error;
    }
  }

  async getCampaignBySlug(slug) {
    try {
      const response = await this.getAll(this.tableIds.campaigns, {
        where: `(Campaign Slug,eq,${slug})`
      });
      return response.list && response.list.length > 0 ? response.list[0] : null;
    } catch (error) {
      console.error('Get campaign by slug failed:', error);
      throw error;
    }
  }

  async createCampaign(campaignData) {
    try {
      // Map field names to NocoDB column titles
      const mappedData = {
        'Campaign Slug': campaignData.slug,
        'Campaign Title': campaignData.title,
        'Description': campaignData.description,
        'Email Subject': campaignData.email_subject,
        'Email Body': campaignData.email_body,
        'Call to Action': campaignData.call_to_action,
        'Cover Photo': campaignData.cover_photo,
        'Status': campaignData.status,
        'Allow SMTP Email': campaignData.allow_smtp_email,
        'Allow Mailto Link': campaignData.allow_mailto_link,
        'Collect User Info': campaignData.collect_user_info,
        'Show Email Count': campaignData.show_email_count,
        'Allow Email Editing': campaignData.allow_email_editing,
        'Target Government Levels': campaignData.target_government_levels,
        'Created By User ID': campaignData.created_by_user_id,
        'Created By User Email': campaignData.created_by_user_email,
        'Created By User Name': campaignData.created_by_user_name
      };
      
      const response = await this.create(this.tableIds.campaigns, mappedData);
      return response;
    } catch (error) {
      console.error('Create campaign failed:', error);
      throw error;
    }
  }

  async updateCampaign(id, updates) {
    try {
      // Map field names to NocoDB column titles
      const mappedUpdates = {};
      
      if (updates.slug !== undefined) mappedUpdates['Campaign Slug'] = updates.slug;
      if (updates.title !== undefined) mappedUpdates['Campaign Title'] = updates.title;
      if (updates.description !== undefined) mappedUpdates['Description'] = updates.description;
      if (updates.email_subject !== undefined) mappedUpdates['Email Subject'] = updates.email_subject;
      if (updates.email_body !== undefined) mappedUpdates['Email Body'] = updates.email_body;
      if (updates.call_to_action !== undefined) mappedUpdates['Call to Action'] = updates.call_to_action;
      if (updates.cover_photo !== undefined) mappedUpdates['Cover Photo'] = updates.cover_photo;
      if (updates.status !== undefined) mappedUpdates['Status'] = updates.status;
      if (updates.allow_smtp_email !== undefined) mappedUpdates['Allow SMTP Email'] = updates.allow_smtp_email;
      if (updates.allow_mailto_link !== undefined) mappedUpdates['Allow Mailto Link'] = updates.allow_mailto_link;
      if (updates.collect_user_info !== undefined) mappedUpdates['Collect User Info'] = updates.collect_user_info;
      if (updates.show_email_count !== undefined) mappedUpdates['Show Email Count'] = updates.show_email_count;
      if (updates.allow_email_editing !== undefined) mappedUpdates['Allow Email Editing'] = updates.allow_email_editing;
      if (updates.target_government_levels !== undefined) mappedUpdates['Target Government Levels'] = updates.target_government_levels;
      if (updates.updated_at !== undefined) mappedUpdates['UpdatedAt'] = updates.updated_at;
      
      const url = `${this.getTableUrl(this.tableIds.campaigns)}/${id}`;
      const response = await this.client.patch(url, mappedUpdates);
      return response.data;
    } catch (error) {
      console.error('Update campaign failed:', error);
      throw error;
    }
  }

  async deleteCampaign(id) {
    try {
      const url = `${this.getTableUrl(this.tableIds.campaigns)}/${id}`;
      const response = await this.client.delete(url);
      return response.data;
    } catch (error) {
      console.error('Delete campaign failed:', error);
      throw error;
    }
  }

  // Campaign email tracking methods
  async logCampaignEmail(emailData) {
    try {
      // Map fields to NocoDB column titles
      const mappedData = {
        'Campaign ID': emailData.campaign_id,
        'Campaign Slug': emailData.campaign_slug,
        'User Email': emailData.user_email,
        'User Name': emailData.user_name,
        'User Postal Code': emailData.user_postal_code,
        'Recipient Email': emailData.recipient_email,
        'Recipient Name': emailData.recipient_name,
        'Recipient Title': emailData.recipient_title,
        'Government Level': emailData.recipient_level,
        'Email Method': emailData.email_method,
        'Subject': emailData.subject,
        'Message': emailData.message,
        'Status': emailData.status
        // Note: 'Sent At' has default value of now() so we don't need to set it
      };
      
      try {
        const response = await this.create(this.tableIds.campaignEmails, mappedData);
        return response;
      } catch (createError) {
        // Handle duplicate record errors gracefully
        if (createError.response?.status === 400 && 
            (createError.response?.data?.message?.includes('already exists') ||
             createError.response?.data?.code === '23505')) {
          console.log(`Campaign email log already exists for user ${emailData.user_email} and campaign ${emailData.campaign_slug}, skipping...`);
          // Return a success response to indicate the logging was handled
          return { success: true, duplicate: true };
        } else {
          // Re-throw other errors
          throw createError;
        }
      }
    } catch (error) {
      console.error('Log campaign email failed:', error.response?.data || error.message);
      // Return a failure response but don't throw - logging should not break the main flow
      return { success: false, error: error.message };
    }
  }

  async getCampaignEmailCount(campaignId) {
    try {
      const response = await this.getAll(this.tableIds.campaignEmails, {
        where: `(Campaign ID,eq,${campaignId})`,
        limit: 1000  // Get enough to count
      });
      return response.pageInfo ? response.pageInfo.totalRows : (response.list ? response.list.length : 0);
    } catch (error) {
      console.error('Get campaign email count failed:', error);
      return 0;
    }
  }

  async getCampaignCallCount(campaignId) {
    try {
      if (!this.tableIds.calls) {
        console.warn('Calls table not configured, returning 0');
        return 0;
      }
      
      const response = await this.getAll(this.tableIds.calls, {
        where: `(Campaign ID,eq,${campaignId})`,
        limit: 1000  // Get enough to count
      });
      return response.pageInfo ? response.pageInfo.totalRows : (response.list ? response.list.length : 0);
    } catch (error) {
      console.error('Get campaign call count failed:', error);
      return 0;
    }
  }

  async getCampaignAnalytics(campaignId) {
    try {
      const response = await this.getAll(this.tableIds.campaignEmails, {
        where: `(Campaign ID,eq,${campaignId})`,
        limit: 1000
      });

      const emails = response.list || [];
      
      const analytics = {
        totalEmails: emails.length,
        smtpEmails: emails.filter(e => (e['Email Method'] || e.email_method) === 'smtp').length,
        mailtoClicks: emails.filter(e => (e['Email Method'] || e.email_method) === 'mailto').length,
        successfulEmails: emails.filter(e => {
          const status = e['Status'] || e.status;
          return status === 'sent' || status === 'clicked';
        }).length,
        failedEmails: emails.filter(e => (e['Status'] || e.status) === 'failed').length,
        byLevel: {},
        byDate: {},
        recentEmails: emails.slice(0, 10).map(email => ({
          timestamp: email['Sent At'] || email.timestamp || email.sent_at,
          user_name: email['User Name'] || email.user_name,
          recipient_name: email['Recipient Name'] || email.recipient_name,
          recipient_level: email['Government Level'] || email.recipient_level,
          email_method: email['Email Method'] || email.email_method,
          status: email['Status'] || email.status
        }))
      };

      // Group by government level
      emails.forEach(email => {
        const level = email['Government Level'] || email.recipient_level || 'Other';
        analytics.byLevel[level] = (analytics.byLevel[level] || 0) + 1;
      });

      // Group by date
      emails.forEach(email => {
        const timestamp = email['Sent At'] || email.timestamp || email.sent_at;
        if (timestamp) {
          const date = timestamp.split('T')[0]; // Get date part
          analytics.byDate[date] = (analytics.byDate[date] || 0) + 1;
        }
      });

      return analytics;
    } catch (error) {
      console.error('Get campaign analytics failed:', error);
      return {
        totalEmails: 0,
        smtpEmails: 0,
        mailtoClicks: 0,
        successfulEmails: 0,
        failedEmails: 0,
        byLevel: {},
        byDate: {},
        recentEmails: []
      };
    }
  }

  // User management methods
  async getUserByEmail(email) {
    if (!this.tableIds.users) {
      throw new Error('Users table not configured');
    }

    try {
      const response = await this.getAll(this.tableIds.users, {
        where: `(Email,eq,${email})`,
        limit: 1
      });

      return response.list?.[0] || null;
    } catch (error) {
      console.error('Error in getUserByEmail:', error.message);
      throw error;
    }
  }

  async createUser(userData) {
    if (!this.tableIds.users) {
      throw new Error('Users table not configured');
    }
    
    return await this.create(this.tableIds.users, userData);
  }

  async updateUser(userId, userData) {
    if (!this.tableIds.users) {
      throw new Error('Users table not configured');
    }
    
    return await this.update(this.tableIds.users, userId, userData);
  }

  async deleteUser(userId) {
    if (!this.tableIds.users) {
      throw new Error('Users table not configured');
    }

    const url = `${this.getTableUrl(this.tableIds.users)}/${userId}`;
    const response = await this.client.delete(url);
    return response.data;
  }

  async getById(tableId, recordId) {
    try {
      const url = `${this.getTableUrl(tableId)}/${recordId}`;
      const response = await this.client.get(url);
      return response.data;
    } catch (error) {
      console.error('Error getting record by ID:', error);
      throw error;
    }
  }

  async getAllUsers(params = {}) {
    if (!this.tableIds.users) {
      throw new Error('Users table not configured');
    }
    
    return await this.getAll(this.tableIds.users, params);
  }

  // Representative Responses methods
  async getRepresentativeResponses(params = {}) {
    if (!this.tableIds.representativeResponses) {
      throw new Error('Representative responses table not configured');
    }
    console.log('getRepresentativeResponses params:', JSON.stringify(params, null, 2));
    const result = await this.getAll(this.tableIds.representativeResponses, params);
    
    // Log without the where clause to see ALL responses
    if (params.where) {
      const allResult = await this.getAll(this.tableIds.representativeResponses, {});
      console.log(`Total responses in DB (no filter): ${allResult.list?.length || 0}`);
      if (allResult.list && allResult.list.length > 0) {
        console.log('Sample raw response from DB:', JSON.stringify(allResult.list[0], null, 2));
      }
    }
    
    console.log('getRepresentativeResponses raw result:', JSON.stringify(result, null, 2));
    // NocoDB returns {list: [...]} or {pageInfo: {...}, list: [...]}
    const list = result.list || [];
    console.log(`getRepresentativeResponses: Found ${list.length} responses`);
    return list.map(item => this.normalizeResponse(item));
  }

  async getRepresentativeResponseById(responseId) {
    if (!this.tableIds.representativeResponses) {
      throw new Error('Representative responses table not configured');
    }
    try {
      const url = `${this.getTableUrl(this.tableIds.representativeResponses)}/${responseId}`;
      const response = await this.client.get(url);
      return this.normalizeResponse(response.data);
    } catch (error) {
      console.error('Error getting representative response by ID:', error);
      throw error;
    }
  }

  async createRepresentativeResponse(responseData) {
    if (!this.tableIds.representativeResponses) {
      throw new Error('Representative responses table not configured');
    }

    // Ensure campaign_id is not null/undefined
    if (!responseData.campaign_id) {
      throw new Error('Campaign ID is required for creating a response');
    }

    const data = {
      'Campaign ID': responseData.campaign_id,
      'Campaign Slug': responseData.campaign_slug,
      'Representative Name': responseData.representative_name,
      'Representative Title': responseData.representative_title,
      'Representative Level': responseData.representative_level,
      'Response Type': responseData.response_type,
      'Response Text': responseData.response_text,
      'User Comment': responseData.user_comment,
      'Screenshot URL': responseData.screenshot_url,
      'Submitted By Name': responseData.submitted_by_name,
      'Submitted By Email': responseData.submitted_by_email,
      'Submitted By User ID': responseData.submitted_by_user_id,
      'Is Anonymous': responseData.is_anonymous,
      'Status': responseData.status,
      'Is Verified': responseData.is_verified,
      'Upvote Count': responseData.upvote_count,
      'Submitted IP': responseData.submitted_ip
    };

    console.log('Creating response with data:', JSON.stringify(data, null, 2));

    const url = this.getTableUrl(this.tableIds.representativeResponses);
    const response = await this.client.post(url, data);
    return this.normalizeResponse(response.data);
  }

  async updateRepresentativeResponse(responseId, updates) {
    if (!this.tableIds.representativeResponses) {
      throw new Error('Representative responses table not configured');
    }

    const data = {};
    if (updates.status !== undefined) data['Status'] = updates.status;
    if (updates.is_verified !== undefined) data['Is Verified'] = updates.is_verified;
    if (updates.upvote_count !== undefined) data['Upvote Count'] = updates.upvote_count;
    if (updates.response_text !== undefined) data['Response Text'] = updates.response_text;
    if (updates.user_comment !== undefined) data['User Comment'] = updates.user_comment;

    console.log(`Updating response ${responseId} with data:`, JSON.stringify(data, null, 2));

    const url = `${this.getTableUrl(this.tableIds.representativeResponses)}/${responseId}`;
    const response = await this.client.patch(url, data);
    
    console.log('NocoDB update response:', JSON.stringify(response.data, null, 2));
    
    return this.normalizeResponse(response.data);
  }

  async deleteRepresentativeResponse(responseId) {
    if (!this.tableIds.representativeResponses) {
      throw new Error('Representative responses table not configured');
    }
    const url = `${this.getTableUrl(this.tableIds.representativeResponses)}/${responseId}`;
    const response = await this.client.delete(url);
    return response.data;
  }

  // Response Upvotes methods
  async getResponseUpvotes(params = {}) {
    if (!this.tableIds.responseUpvotes) {
      throw new Error('Response upvotes table not configured');
    }
    const result = await this.getAll(this.tableIds.responseUpvotes, params);
    // NocoDB returns {list: [...]} or {pageInfo: {...}, list: [...]}
    const list = result.list || [];
    return list.map(item => this.normalizeUpvote(item));
  }

  async createResponseUpvote(upvoteData) {
    if (!this.tableIds.responseUpvotes) {
      throw new Error('Response upvotes table not configured');
    }

    const data = {
      'Response ID': upvoteData.response_id,
      'User ID': upvoteData.user_id,
      'User Email': upvoteData.user_email,
      'Upvoted IP': upvoteData.upvoted_ip
    };

    const url = this.getTableUrl(this.tableIds.responseUpvotes);
    const response = await this.client.post(url, data);
    return this.normalizeUpvote(response.data);
  }

  async deleteResponseUpvote(upvoteId) {
    if (!this.tableIds.responseUpvotes) {
      throw new Error('Response upvotes table not configured');
    }
    const url = `${this.getTableUrl(this.tableIds.responseUpvotes)}/${upvoteId}`;
    const response = await this.client.delete(url);
    return response.data;
  }

  // Normalize response data from NocoDB format to application format
  normalizeResponse(data) {
    if (!data) return null;
    
    return {
      id: data.ID || data.Id || data.id,
      campaign_id: data['Campaign ID'] || data.campaign_id,
      campaign_slug: data['Campaign Slug'] || data.campaign_slug,
      representative_name: data['Representative Name'] || data.representative_name,
      representative_title: data['Representative Title'] || data.representative_title,
      representative_level: data['Representative Level'] || data.representative_level,
      response_type: data['Response Type'] || data.response_type,
      response_text: data['Response Text'] || data.response_text,
      user_comment: data['User Comment'] || data.user_comment,
      screenshot_url: data['Screenshot URL'] || data.screenshot_url,
      submitted_by_name: data['Submitted By Name'] || data.submitted_by_name,
      submitted_by_email: data['Submitted By Email'] || data.submitted_by_email,
      submitted_by_user_id: data['Submitted By User ID'] || data.submitted_by_user_id,
      is_anonymous: data['Is Anonymous'] || data.is_anonymous || false,
      status: data['Status'] || data.status,
      is_verified: data['Is Verified'] || data.is_verified || false,
      upvote_count: data['Upvote Count'] || data.upvote_count || 0,
      submitted_ip: data['Submitted IP'] || data.submitted_ip,
      created_at: data.CreatedAt || data.created_at,
      updated_at: data.UpdatedAt || data.updated_at
    };
  }

  // Normalize upvote data from NocoDB format to application format
  normalizeUpvote(data) {
    if (!data) return null;
    
    return {
      id: data.ID || data.Id || data.id,
      response_id: data['Response ID'] || data.response_id,
      user_id: data['User ID'] || data.user_id,
      user_email: data['User Email'] || data.user_email,
      upvoted_ip: data['Upvoted IP'] || data.upvoted_ip,
      created_at: data.CreatedAt || data.created_at
    };
  }
}

module.exports = new NocoDBService();
