const crypto = require('crypto');
const dns = require('dns').promises;
const { ethers } = require('ethers');
const db = require('../database/db');

/**
 * Generates a unique verification token for domain ownership
 * @param {string} userId - User's UUID
 * @param {string} domain - Domain to verify (e.g., dev.aethex.dev)
 * @returns {Promise<Object>} Verification instructions
 */
async function generateDomainVerificationToken(userId, domain) {
  // Generate random 32-byte token
  const token = crypto.randomBytes(32).toString('hex');
  
  // Store in database
  await db.query(
    `INSERT INTO domain_verifications 
     (user_id, domain, verification_token, verification_type)
     VALUES ($1, $2, $3, 'dns')
     ON CONFLICT (user_id, domain) 
     DO UPDATE SET verification_token = $3, created_at = NOW(), expires_at = NOW() + INTERVAL '7 days', verified = false`,
    [userId, domain, token]
  );
  
  return {
    domain: domain,
    recordType: 'TXT',
    recordName: '_aethex-verify',
    recordValue: `aethex-verification=${token}`,
    fullRecord: `_aethex-verify.${domain} TXT "aethex-verification=${token}"`,
    expiresAt: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString()
  };
}

/**
 * Verifies domain ownership by checking DNS TXT records
 * @param {string} userId - User's UUID
 * @param {string} domain - Domain to verify
 * @returns {Promise<Object>} Verification result
 */
async function verifyDomainOwnership(userId, domain) {
  try {
    // Get stored verification token
    const result = await db.query(
      'SELECT verification_token, expires_at FROM domain_verifications WHERE user_id = $1 AND domain = $2',
      [userId, domain]
    );
    
    if (result.rows.length === 0) {
      return { verified: false, error: 'No verification request found' };
    }
    
    const { verification_token: expectedToken, expires_at: expiresAt } = result.rows[0];
    
    // Check if verification request has expired
    if (new Date() > new Date(expiresAt)) {
      return { verified: false, error: 'Verification request has expired. Please request a new verification.' };
    }
    
    // Query DNS for TXT records
    const txtRecords = await dns.resolveTxt(`_aethex-verify.${domain}`);
    
    // Flatten nested arrays that DNS returns
    const flatRecords = txtRecords.flat();
    
    // Check if our token exists
    const verified = flatRecords.some(record => 
      record.includes(`aethex-verification=${expectedToken}`)
    );
    
    if (verified) {
      // Update database
      await db.query(
        `UPDATE domain_verifications 
         SET verified = true, verified_at = NOW() 
         WHERE user_id = $1 AND domain = $2`,
        [userId, domain]
      );
      
      await db.query(
        `UPDATE users 
         SET verified_domain = $2, domain_verified_at = NOW() 
         WHERE id = $1`,
        [userId, domain]
      );
      
      return { 
        verified: true, 
        domain: domain,
        verifiedAt: new Date()
      };
    }
    
    return { 
      verified: false, 
      error: 'Verification token not found in DNS records. Please ensure the TXT record has been added and DNS has propagated (5-10 minutes).' 
    };
    
  } catch (error) {
    // DNS lookup failed (domain doesn't exist, no TXT records, etc.)
    if (error.code === 'ENOTFOUND' || error.code === 'ENODATA') {
      return { 
        verified: false, 
        error: 'DNS lookup failed: TXT record not found. Please ensure you\'ve added the record and wait 5-10 minutes for DNS propagation.' 
      };
    }
    
    return { 
      verified: false, 
      error: `DNS lookup failed: ${error.message}` 
    };
  }
}

/**
 * Verifies .aethex domain ownership via blockchain
 * @param {string} userId - User's UUID
 * @param {string} domain - Domain to verify (e.g., anderson.aethex)
 * @param {string} walletAddress - User's connected wallet address
 * @returns {Promise<Object>} Verification result
 */
async function verifyAethexDomain(userId, domain, walletAddress) {
  try {
    // Connect to blockchain (Polygon/Ethereum)
    const provider = new ethers.JsonRpcProvider(process.env.RPC_ENDPOINT);
    
    // Freename contract ABI (simplified - you'll need the actual ABI)
    // This is a minimal ERC721-like interface
    const FREENAME_ABI = [
      "function ownerOf(string memory domain) view returns (address)",
      "function getDomainOwner(string memory domain) view returns (address)"
    ];
    
    const contract = new ethers.Contract(
      process.env.FREENAME_REGISTRY_ADDRESS,
      FREENAME_ABI,
      provider
    );
    
    // Query who owns this .aethex domain
    // Try both common method names
    let owner;
    try {
      owner = await contract.ownerOf(domain);
    } catch (e) {
      owner = await contract.getDomainOwner(domain);
    }
    
    // Check if connected wallet owns the domain
    const verified = owner.toLowerCase() === walletAddress.toLowerCase();
    
    if (verified) {
      // Store verification
      await db.query(
        `INSERT INTO domain_verifications 
         (user_id, domain, verification_token, verification_type, verified, verified_at)
         VALUES ($1, $2, $3, 'blockchain', true, NOW())
         ON CONFLICT (user_id, domain) 
         DO UPDATE SET verified = true, verified_at = NOW()`,
        [userId, domain, walletAddress]
      );
      
      await db.query(
        `UPDATE users 
         SET verified_domain = $2, domain_verified_at = NOW() 
         WHERE id = $1`,
        [userId, domain]
      );
      
      return { 
        verified: true, 
        domain: domain,
        verifiedAt: new Date()
      };
    }
    
    return { 
      verified: false, 
      error: 'Wallet does not own this domain. The domain is owned by a different address.' 
    };
    
  } catch (error) {
    return { 
      verified: false, 
      error: `Blockchain verification failed: ${error.message}` 
    };
  }
}

/**
 * Get verification status for a user
 * @param {string} userId - User's UUID
 * @returns {Promise<Object>} Verification status
 */
async function getVerificationStatus(userId) {
  const result = await db.query(
    `SELECT verified_domain, domain_verified_at FROM users WHERE id = $1`,
    [userId]
  );
  
  if (result.rows.length === 0) {
    return { hasVerifiedDomain: false };
  }
  
  const { verified_domain, domain_verified_at } = result.rows[0];
  
  if (!verified_domain) {
    return { hasVerifiedDomain: false };
  }
  
  // Get verification type
  const verificationInfo = await db.query(
    `SELECT verification_type FROM domain_verifications 
     WHERE user_id = $1 AND domain = $2 AND verified = true
     ORDER BY verified_at DESC LIMIT 1`,
    [userId, verified_domain]
  );
  
  return {
    hasVerifiedDomain: true,
    domain: verified_domain,
    verifiedAt: domain_verified_at,
    verificationType: verificationInfo.rows[0]?.verification_type || 'dns'
  };
}

/**
 * Clean up expired verification requests
 * Should be run periodically (e.g., daily cron job)
 */
async function cleanupExpiredVerifications() {
  const result = await db.query(
    `DELETE FROM domain_verifications 
     WHERE verified = false AND expires_at < NOW()
     RETURNING id`
  );
  
  console.log(`Cleaned up ${result.rowCount} expired verification requests`);
  return result.rowCount;
}

module.exports = {
  generateDomainVerificationToken,
  verifyDomainOwnership,
  verifyAethexDomain,
  getVerificationStatus,
  cleanupExpiredVerifications
};
