import express from 'express';
import { createProxyServer } from 'http-proxy';
import zlib from 'zlib';
import fs from 'fs';
import path from 'path';

let originalUrl: string | undefined  = undefined;

const app = express();
const proxy = createProxyServer({
  target: 'http://google.com', // Replace with your target URL
  changeOrigin: true,
  // ignorePath: true,
  selfHandleResponse: true, // Required for modifying the response
    // onProxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) => {
    //   let response = responseBuffer.toString('utf8');

    //   // Convert relative URLs to absolute URLs
    //   response = response.replace(/(href|src)="\/([^"]+)"/g, `$1="http://google.com/$2"`);

    //   return response;
    // }),
});

// app.use('/hardcodedproxy', proxy('www.google.com'));

// proxy.on('proxyRes', (proxyRes, req, res) => {
//   let body: Buffer[] = [];

//   proxyRes.on('data', (chunk) => {
//     body.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
//   });

//   proxyRes.on('end', () => {
//     let rawBody = Buffer.concat(body);

//     // Get content type
//     const contentType = proxyRes.headers['content-type'] || '';

//     // Handle decompression safely
//     try {
//       if (proxyRes.headers['content-encoding']) {
//         if (proxyRes.headers['content-encoding'].includes('gzip')) {
//           rawBody = zlib.gunzipSync(rawBody);
//         } else if (proxyRes.headers['content-encoding'].includes('br')) {
//           rawBody = zlib.brotliDecompressSync(rawBody);
//         } else if (proxyRes.headers['content-encoding'].includes('deflate')) {
//           rawBody = zlib.inflateSync(rawBody);
//         }

//         delete proxyRes.headers['content-encoding']; // Let the browser handle plain text
//       }
//     } catch (err) {
//       console.error('Decompression failed:', err);
//     }

//     // Modify HTML only
//     if (contentType.includes('text/html')) {
//       let response = rawBody.toString('utf8');
//       response = response.replace(/<head>/, `<head><base href="https://www.bosch-diy.com/">`);
//       rawBody = Buffer.from(response, 'utf8');
//     }

//     // 🔹 Set CORS headers dynamically after modifications
//     res.setHeader('Access-Control-Allow-Origin', '*');
//     res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
//     res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

//     // 🔹 Allow CORS for static assets
//     if (
//       contentType.includes('font') ||
//       contentType.includes('css') ||
//       contentType.includes('javascript') ||
//       contentType.includes('image')
//     ) {
//       res.setHeader('Access-Control-Allow-Origin', '*');
//     }

//     res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
//     res.end(rawBody);
//   });
// });

const getBaseUrl = (urlString: string): string => {
  try {
      const url = new URL(urlString);
      const baseDomain = url.hostname; // Get the base domain
      const protocol = url.protocol; // Get the protocol (includes ':' at the end)

      // Format the output as needed
      const output = {
          protocol: protocol, // e.g., 'https:'
          baseDomain: baseDomain // e.g., 'www.example.com'
      };

      return protocol + '://' + baseDomain;
  } catch (error) {
      return '';
  }
};

proxy.on('proxyReq', (proxyReq, req) => {
  // Forward necessary headers
  proxyReq.setHeader('User-Agent', req.headers['user-agent'] || '');
  proxyReq.setHeader('Accept-Language', req.headers['accept-language'] || '');
  proxyReq.setHeader('Cookie', req.headers['cookie'] || ''); // Ensure cookies are forwarded
});

proxy.on('proxyRes', (proxyRes, req, res) => {
  let body: Buffer[] = [];
  delete proxyRes.headers['content-length'];

  proxyRes.on('data', (chunk) => {
    body.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
  });

  proxyRes.on('end', () => {
    let rawBody = Buffer.concat(body);

    // Handle decompression safely
    try {
      if (proxyRes.headers['content-encoding']) {
        if (proxyRes.headers['content-encoding'].includes('gzip')) {
          rawBody = zlib.gunzipSync(rawBody);
        } else if (proxyRes.headers['content-encoding'].includes('br')) {
          rawBody = zlib.brotliDecompressSync(rawBody);
        } else if (proxyRes.headers['content-encoding'].includes('deflate')) {
          rawBody = zlib.inflateSync(rawBody);
        }

        delete proxyRes.headers['content-encoding']; // Let the browser handle plain text
      }
    } catch (err) {
      console.error('Decompression failed:', err);
    }

    // Modify HTML only
    const contentType = proxyRes.headers['content-type'] || '';
    if (contentType.includes('text/html')) {
      let response = rawBody.toString('utf8');
      const filePath = path.join(__dirname, 'original_response.html');
      fs.writeFile(filePath, response, (err) => {
        if (err) {
            console.error('Error writing to file', err);
          }
        console.error('Successtully writing response to file', err);
    });

    // Debugging
    console.log("Received HTML Length:", response.length);
    console.log('checking if __NEXT_DATA__ exists in response:');
    if (!rawBody.toString().includes('__NEXT_DATA__')) {
      console.warn("🚨 __NEXT_DATA__ is missing from final response! 🚨");
    } else {
      console.log("✅ __NEXT_DATA__ exists in final response.");
    }

      // const oU = originalUrl || 'https://www.bosch-diy.com';
      const oU = originalUrl ? getBaseUrl(originalUrl) : '';
      // Add a <base> tag to ensure relative URLs resolve correctly
      response = response.replace(/<head>/, `<head><base href="${oU}">`);

      // Rewrite only relative URLs to absolute URLs
      response = response.replace(/(href|src)="\/([^"]+)"/g, `$1="${oU}/$2"`);

      // force all internal navigation to go trough the proxy
      const overrideScript = `
        <script>
          (function() {
            const originalPushState = window.history.pushState;
            const originalReplaceState = window.history.replaceState;

            function sanitizeUrl(url) {
              if (!url.startsWith('/') && !url.startsWith(window.location.origin)) {
                console.warn('🔍 Blocking navigation to external URL:', url);
                return window.location.pathname; // Stay on the same page
              }
              return url;
            }

            window.history.pushState = function(state, title, url) {
              return originalPushState.call(this, state, title, sanitizeUrl(url));
            };

            window.history.replaceState = function(state, title, url) {
              return originalReplaceState.call(this, state, title, sanitizeUrl(url));
            };
          })();
        </script>`;

        const overrideScriptToSolvePushState_orig = `
          <script>
            (function() {
              function sanitizeUrl(url) {
                // If the URL is trying to go to another origin, block it
                if (!url.startsWith(window.location.origin)) {
                  console.warn('🚫 Blocking cross-origin replaceState:', url);
                  return window.location.pathname; // Stay on the same page
                }
                return url;
              }

              function overrideHistoryMethod(method) {
                const original = history[method];

                Object.defineProperty(history, method, {
                  configurable: false,
                  enumerable: false,
                  writable: false,
                  value: function(state, title, url) {
                    const safeUrl = sanitizeUrl(url);
                    try {
                      return original.call(this, state, title, safeUrl);
                    } catch (e) {
                      console.error(\`❌ History. error prevented:\`, e);
                    }
                  }
                });
              }

              overrideHistoryMethod('replaceState');
              overrideHistoryMethod('pushState');

              console.log('✅ History override (Object.defineProperty) injected');
            })();
          </script>`;

          const overrideScriptToSolvePushState = `
          <script>
    (function() {
      console.log('✅ Injecting domain and history overrides...');

      // Override history.replaceState to prevent cross-origin errors
      const originalReplaceState = window.history.replaceState;
      window.history.replaceState = function(state, title, url) {
        try {
          if (url && url.startsWith("https://www.bosch-diy.com")) {
            console.warn("🚨 Prevented replaceState to", url);
            return;
          }
          originalReplaceState.apply(this, arguments);
          console.log("✅ replaceState called with:", state, title, url);
        } catch (e) {
          console.error("❌ Error in replaceState override:", e);
        }
      };

      console.log("✅ history.replaceState overridden successfully");
    })();
  </script>`;

  const fixDomainScript = `
  <script>
    console.log('✅ Injecting document.domain fix...');

    try {
      document.domain = "localhost";
      console.log("✅ document.domain set to localhost");
    } catch (e) {
      console.warn("❌ Unable to set document.domain:", e);
    }
  </script>`;

        console.log("🔹 Adding override script to response");
      response = response.replace('</head>', `${overrideScriptToSolvePushState}${fixDomainScript}${overrideScript}</head>`);


      rawBody = Buffer.from(response, 'utf8');

      const encoding = proxyRes.headers['content-encoding'] || '';
      console.log("🔄 Encoding Type:", encoding);

      if (encoding.includes('gzip')) {
        rawBody = zlib.gunzipSync(rawBody);
      } else if (encoding.includes('br')) {
        rawBody = zlib.brotliDecompressSync(rawBody);
      } else if (encoding.includes('deflate')) {
        rawBody = zlib.inflateSync(rawBody);
      }

      delete proxyRes.headers['content-encoding']; // Remove encoding header
      if (proxyRes.headers['set-cookie']) {
        proxyRes.headers['set-cookie'] = proxyRes.headers['set-cookie'].map(cookie =>
          cookie.replace(/Domain=\.?bosch-diy\.com/gi, 'Domain=localhost').replace(/Secure;/gi, '') // Remove Secure for local dev
        );
      }
      if (proxyRes.headers['content-security-policy']) {
        delete proxyRes.headers['content-security-policy']; // Remove CSP
      }
      if (proxyRes.headers['content-security-policy-report-only']) {
        delete proxyRes.headers['content-security-policy-report-only']; // Remove CSP report-only mode
      }
    }

    // 🔹 Set CORS headers dynamically for all responses
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
    res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate, proxy-revalidate');
    res.setHeader('Pragma', 'no-cache');
    res.setHeader('Expires', '0');

    res.writeHead(proxyRes.statusCode || 200, proxyRes.headers);
    res.end(rawBody);
  });
});





app.get('/proxy', (req, res) => {
  const oU = req.query.url;
  console.log('originalUrl:', oU)
  if (!oU || typeof oU !== 'string') {
    return res.status(400).send('Please provide a valid URL as a string');
  }
  originalUrl = oU;

  req.url = req.url.replace(/^\/proxy/, '/search');
  console.log('req.url:', req.url)

  // console.log('proxy:', proxy)
  proxy.web(req, res, { target: originalUrl });
});

// // Serve frontend static files
// const distDir = path.join(__dirname, '../frontend/build'); // Adjust this if your frontend build output is different
// app.use(express.static(distDir));

// app.get('*', (req, res) => {
//   res.sendFile(path.join(__dirname, '../../frontend/build', 'index.html')); // Serve the frontend
// });

const port = process.env.PORT || 3005;

app.listen(port, () => {
  console.log(`Server listening on port ${port}`);
});