require('dotenv').config();
const OAuth = require('oauth-1.0a');
const crypto = require('crypto');

// Get API credentials from environment variables.
// For a real application, both API_ACCESS_KEY and API_ACCESS_SECRET should be set.
const validApiKey = process.env.API_ACCESS_KEY || "chamith";
const validApiSecret = process.env.API_ACCESS_SECRET || "pFjMsz1orZWKzgS90_j4kXwqYs9l7C_GPglYTkjWR8Q";

if (!validApiKey || !validApiSecret) {
  //console.error("Environment variables API_ACCESS_KEY or API_ACCESS_SECRET are missing.");
  process.exit(1);
}

// Use the raw consumer secret (trimmed) without any URL encoding.
// This is important because for two-legged OAuth the signing key is:
// consumerSecret + "&", and in three-legged OAuth it will be consumerSecret + "&" + tokenSecret.
const rawConsumerSecret = validApiSecret.trim();
const signingKey = rawConsumerSecret + "&";
//console.log("Raw Consumer Secret (no encoding):", rawConsumerSecret);

const oauth = new OAuth({
  consumer: {
    key: validApiKey,
        secret: signingKey
  },
  signature_method: 'HMAC-SHA1',
  includeBodyHash: false,
  hash_function(baseString, key) {
    return crypto.createHmac('sha1', key)
      .update(baseString)
      .digest('base64');
  }
});

const authorize = (req, res, next) => {
//   console.log("Incoming request:", req.method, req.originalUrl);

  const authHeader = req.headers['authorization'];
  if (!authHeader) {
    // console.error("Authorization header is missing");
    return res.status(403).json({ message: 'Authorization header is missing' });
  }
//   console.log("Authorization header:", authHeader);

  // Parse the OAuth header (e.g., OAuth param1="value1", param2="value2", ...)
  const oauth_data = authHeader
    .replace(/^OAuth\s/, '')
    .split(/,\s*(?=\w+="[^"]*")/)
    .reduce((params, param) => {
      const [key, value] = param.split('=');
      params[key.trim()] = value.replace(/"/g, '').trim();
      return params;
    }, {});
  //console.log("Parsed header parameters:", oauth_data);

  // For development purposes, you can override nonce and timestamp
  // if (process.env.NODE_ENV === 'development') {
  //   oauth_data.oauth_nonce = 'fixedNonce123';
  //   oauth_data.oauth_timestamp = '1743251328';
  // }

  // Validate required OAuth parameters
  const requiredParams = [
      'oauth_consumer_key',
      'oauth_nonce',
      'oauth_signature_method',
      'oauth_timestamp',
      'oauth_signature',
      'oauth_version',
  ];
  for (const param of requiredParams) {
    if (!oauth_data[param]) {
      //console.error(`Missing required OAuth parameter: ${param}`);
      return res.status(403).json({ message: `Missing OAuth parameter: ${param}` });
    }
  }

  if (oauth_data.oauth_consumer_key !== validApiKey) {
    //console.error("Invalid consumer key:", oauth_data.oauth_consumer_key);
    return res.status(403).json({ message: 'Invalid consumer key' });
  }

  // Clean the URL by removing the oauth_signature query parameter if present.
  //const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`;
  const fullUrl = `https://api.bobros.org${req.originalUrl}`;
  
  const parsedUrl = new URL(fullUrl);
  parsedUrl.searchParams.delete('oauth_signature');
  const sortedParams = new URLSearchParams([...parsedUrl.searchParams].sort());
  parsedUrl.search = sortedParams.toString();
  const normalizedUrl = parsedUrl.toString();
    // console.log("Normalized Url:", normalizedUrl);
  // Prepare request data for signature verification
  const requestData = {
    url: normalizedUrl,
    method: req.method,
    data: {} // data: req.method === 'GET' ? {} : req.body || {}
  };

  try {
    // Copy the oauth data without the oauth_signature for generating the base string.
      //const oauthDataForSignature = { ...oauth_data };
      const oauthDataForSignature = {
          oauth_consumer_key: oauth_data.oauth_consumer_key,
          oauth_signature_method: oauth_data.oauth_signature_method,
          oauth_timestamp: oauth_data.oauth_timestamp,
          oauth_nonce: oauth_data.oauth_nonce,
          oauth_version: oauth_data.oauth_version
      };
      //console.log("OAuth keys before deletion:", Object.keys(oauthDataForSignature));
    //delete oauthDataForSignature.oauth_signature;
    //   console.log("OAuth Data for Signature:", oauthDataForSignature);
    //   console.log('Does oauth_signature exist?', 'oauth_signature' in oauthDataForSignature);

    // Determine the token part of the signing key. For two-legged OAuth, leave empty.
    let token = {};
    if (oauth_data.oauth_token && oauth_data.oauth_token_secret) {
      // For three-legged OAuth, include token and token secret.
      token = {
        key: oauth_data.oauth_token,
        secret: oauth_data.oauth_token_secret
      };
    } else {
      // Two-legged OAuth: token is empty.
      token = { key: '', secret: '' };
    // }
    //   //console.log("token:", token);
    //   //console.log("requestData:", requestData);
    // Generate the signature base string.
    const signatureBaseString = oauth.getBaseString(requestData, oauthDataForSignature);
    //   console.log("Signature Base String:", signatureBaseString);
    //   console.log("Signing Key:", signingKey);
      const expectedSignature = crypto
          .createHmac('sha1', signingKey)
          .update(signatureBaseString)
          .digest('base64');
    //   console.log("signature:", expectedSignature);
    // Generate the expected signature using the token (if any).
    //const expectedSignature = oauth.getSignature(requestData, token, oauthDataForSignature);

     //console.log('oauth signature:', oauth_data.oauth_signature);
    // Decode the provided signature in case it is URL-encoded.
    const providedSignature = decodeURIComponent(oauth_data.oauth_signature);

    // console.log('Provided Signature:', providedSignature);
    // console.log('Expected Signature:', expectedSignature);

    // Use constant-time comparison to prevent timing attacks.
    const signatureMatch = crypto.timingSafeEqual(
      Buffer.from(providedSignature),
      Buffer.from(expectedSignature)
    );

    if (!signatureMatch) {
      console.error("Invalid OAuth signature");
      return res.status(403).json({ message: 'Invalid OAuth signature' });
    }

    // If signature matches, proceed to the next middleware / route handler.
    next();
    } 
  }catch (error) {
    console.error("OAuth Signature Verification Error:", error);
    return res.status(500).json({
      message: 'OAuth signature verification failed',
      error: error.message
    });
  
};
}
module.exports = authorize;
