import express from 'express';
import path from 'path';
import fs from 'fs';
import { createServer as createViteServer } from 'vite';
import { paymentStore } from './src/server/payments/store';
import { PaymentService } from './src/server/payments/paymentService';
import { UddoktaPayService } from './src/server/payments/uddoktapay';
import { serverListingsStore } from './src/server/listingsStore';
import { visitorStore } from './src/server/visitorStore';

async function startServer() {
  const app = express();
  const PORT = process.env.PORT || 3000;

  // Middlewares for JSON and Form URL-encoded bodies
  app.use(express.json({ limit: '10mb' }));
  app.use(express.urlencoded({ extended: true, limit: '10mb' }));

  // Helper to determine base URL
  const getAppBaseUrl = (req: express.Request) => {
    if (process.env.APP_URL && process.env.APP_URL.trim() && !process.env.APP_URL.includes('MY_APP_URL')) {
      return process.env.APP_URL.trim().replace(/\/+$/, '');
    }
    const protocol = req.headers['x-forwarded-proto'] || req.protocol || 'http';
    const host = req.headers['x-forwarded-host'] || req.headers.host || `localhost:${PORT}`;
    return `${protocol}://${host}`;
  };

  // ==========================================
  // 1. PUBLIC PAYMENT API ROUTES
  // ==========================================

  // Health check
  app.get('/api/health', (req, res) => {
    res.json({ status: 'ok', timestamp: new Date().toISOString() });
  });

  // Get Server-Ranked Listings (Server-Side Ranking & Pagination)
  app.get('/api/listings', (req, res) => {
    const { category, selectedCategory, timeFilter, search, q, page, limit } = req.query;
    const catId = (category || selectedCategory) as string;
    const tf = timeFilter as string;
    const searchQuery = (search || q) as string;
    const p = page ? parseInt(page as string, 10) : 1;
    const l = limit ? parseInt(limit as string, 10) : 50;

    const result = serverListingsStore.getRankedListings({
      categoryId: catId,
      timeFilter: tf,
      searchQuery: searchQuery,
      page: p,
      limit: l,
    });

    res.json(result);
  });

  // Increment Click
  app.post('/api/listings/:id/click', (req, res) => {
    const { id } = req.params;
    const updated = serverListingsStore.incrementClicks(id);
    res.json({ success: !!updated, listing: updated });
  });

  // Increment Heart
  app.post('/api/listings/:id/heart', (req, res) => {
    const { id } = req.params;
    const updated = serverListingsStore.incrementHearts(id);
    res.json({ success: !!updated, listing: updated });
  });

  // Get Visitor Counters & Settings
  app.get('/api/visitors/stats', (req, res) => {
    const stats = visitorStore.getStats();
    res.json({ success: true, ...stats });
  });

  // Client Ping for Real Active Session & Visitor Tracking
  app.post('/api/visitors/ping', (req, res) => {
    const { clientId } = req.body || {};
    const fallbackId = (req.headers['x-forwarded-for'] as string)?.split(',')[0] || req.socket.remoteAddress || 'anonymous_client';
    const effectiveClientId = clientId && typeof clientId === 'string' && clientId.trim().length > 0 ? clientId.trim() : fallbackId;
    const stats = visitorStore.ping(effectiveClientId);
    res.json({ success: true, ...stats });
  });

  // Get Enabled Public Gateways (no secrets exposed)
  app.get('/api/gateways/public', (req, res) => {
    const gateways = paymentStore.getPublicGateways();
    const defaultGateway = paymentStore.getDefaultGateway();
    res.json({
      success: true,
      gateways,
      defaultGateway,
    });
  });

  // Initiate Payment Session
  app.post('/api/payments/init', async (req, res) => {
    try {
      const { targetListingId, name, url, facebook_url, website_url, imageUrl, categoryId, categoryName, amount, gateway, channel } = req.body;

      const finalFbUrl = facebook_url || url;
      if (!name || !finalFbUrl || !amount || !gateway) {
        return res.status(400).json({
          success: false,
          message: 'Missing required parameters (name, facebook_url, amount, gateway).',
        });
      }

      const clientIp = (req.headers['x-forwarded-for'] as string)?.split(',')[0] || req.socket.remoteAddress;
      const appBaseUrl = getAppBaseUrl(req);

      const result = await PaymentService.initPayment(
        {
          targetListingId,
          name,
          url,
          facebook_url: finalFbUrl,
          website_url,
          imageUrl,
          categoryId: categoryId || 'cat_biz',
          categoryName,
          amount: Number(amount),
          gateway,
          channel,
          customerIp: clientIp,
          originUrl: appBaseUrl,
        },
        appBaseUrl
      );

      return res.json(result);
    } catch (err: any) {
      console.error('Payment init error:', err);
      return res.status(500).json({
        success: false,
        message: err.message || 'Internal server error initializing payment.',
      });
    }
  });

  // Query / Poll Verified Transaction Status
  app.get('/api/payments/status/:transactionId', (req, res) => {
    const { transactionId } = req.params;
    const txn = paymentStore.getTransaction(transactionId);
    if (!txn) {
      return res.status(404).json({ success: false, message: 'Transaction not found.' });
    }

    return res.json({
      success: true,
      transaction: {
        id: txn.id,
        transaction_id: txn.transaction_id,
        listing_id: txn.listing_id,
        listing_name: txn.listing_name,
        listing_url: txn.listing_url,
        facebook_url: txn.facebook_url,
        website_url: txn.website_url,
        listing_image: txn.listing_image,
        category_id: txn.category_id,
        amount: txn.amount,
        currency: txn.currency,
        gateway: txn.gateway,
        mode: txn.mode,
        status: txn.status,
        created_at: txn.created_at,
        updated_at: txn.updated_at,
        paid_at: txn.paid_at,
        failure_reason: txn.failure_reason,
      },
    });
  });

  // ==========================================
  // 2. GATEWAY CALLBACK & RETURN ROUTES
  // ==========================================

  // bKash Return Callback
  app.all('/api/payments/bkash/callback', async (req, res) => {
    try {
      const payload = { ...req.query, ...req.body };
      const result = await PaymentService.handleBkashCallback(payload);

      // If requested via browser GET/POST redirect back to frontend with status query
      const txnId = result.transactionId || (payload.merchantInvoiceNumber as string);
      if (req.accepts('html') && !req.xhr) {
        return res.redirect(`/?payment_status=${result.success ? 'success' : 'failed'}&txn=${txnId}`);
      }

      return res.json(result);
    } catch (err: any) {
      console.error('bKash callback error:', err);
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // SSLCommerz Success / Fail / Cancel Callback
  app.all('/api/payments/sslcommerz/callback', async (req, res) => {
    try {
      const payload = { ...req.query, ...req.body };
      const result = await PaymentService.handleSSLCommerzCallback(payload);

      const txnId = result.transactionId || (payload.tran_id as string);
      if (req.accepts('html') && !req.xhr) {
        return res.redirect(`/?payment_status=${result.success ? 'success' : 'failed'}&txn=${txnId}`);
      }

      return res.json(result);
    } catch (err: any) {
      console.error('SSLCommerz callback error:', err);
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // SSLCommerz IPN (Instant Payment Notification)
  app.post('/api/payments/sslcommerz/ipn', async (req, res) => {
    try {
      const result = await PaymentService.handleSSLCommerzCallback(req.body);
      return res.status(200).send(result.success ? 'IPN_SUCCESS' : 'IPN_FAILED');
    } catch {
      return res.status(500).send('IPN_ERROR');
    }
  });

  // Nagad Return Callback
  app.all('/api/payments/nagad/callback', async (req, res) => {
    try {
      const payload = { ...req.query, ...req.body };
      const result = await PaymentService.handleNagadCallback(payload);

      const txnId = result.transactionId || (payload.order_id as string);
      if (req.accepts('html') && !req.xhr) {
        return res.redirect(`/?payment_status=${result.success ? 'success' : 'failed'}&txn=${txnId}`);
      }

      return res.json(result);
    } catch (err: any) {
      console.error('Nagad callback error:', err);
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // DBBL Rocket Return Callback
  app.all('/api/payments/rocket/callback', async (req, res) => {
    try {
      const payload = { ...req.query, ...req.body };
      const result = await PaymentService.handleRocketCallback(payload);

      const txnId = result.transactionId || (payload.order_id as string);
      if (req.accepts('html') && !req.xhr) {
        return res.redirect(`/?payment_status=${result.success ? 'success' : 'failed'}&txn=${txnId}`);
      }

      return res.json(result);
    } catch (err: any) {
      console.error('Rocket callback error:', err);
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // aamarPay Return Callback (Success, Fail, Cancel)
  app.all('/api/payments/aamarpay/callback', async (req, res) => {
    try {
      const payload = { ...req.query, ...req.body };
      const result = await PaymentService.handleAamarPayCallback(payload);

      const txnId = result.transactionId || (payload.mer_txnid as string) || (payload.tran_id as string);
      if (req.accepts('html') && !req.xhr) {
        return res.redirect(`/?payment_status=${result.success ? 'success' : 'failed'}&txn=${txnId}`);
      }

      return res.json(result);
    } catch (err: any) {
      console.error('aamarPay callback error:', err);
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // aamarPay IPN (Instant Payment Notification)
  app.post('/api/payments/aamarpay/ipn', async (req, res) => {
    try {
      const result = await PaymentService.handleAamarPayCallback(req.body);
      return res.status(200).send(result.success ? 'IPN_SUCCESS' : 'IPN_FAILED');
    } catch {
      return res.status(500).send('IPN_ERROR');
    }
  });

  // UddoktaPay Return Callback (Success, Cancel, Return)
  app.all('/api/payments/uddoktapay/callback', async (req, res) => {
    try {
      const payload = { ...req.query, ...req.body };
      const result = await PaymentService.handleUddoktaPayCallback(payload);

      const txnId = result.transactionId || (payload.txn as string) || (payload.invoice_id as string);
      if (req.accepts('html') && !req.xhr) {
        return res.redirect(`/?payment_status=${result.success ? 'success' : 'failed'}&txn=${txnId}`);
      }

      return res.json(result);
    } catch (err: any) {
      console.error('UddoktaPay callback error:', err);
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // UddoktaPay IPN (Instant Payment Notification / Webhook)
  app.post('/api/payments/uddoktapay/ipn', async (req, res) => {
    try {
      const result = await PaymentService.handleUddoktaPayIpn(req.body, req.headers);
      return res.status(result.success ? 200 : 400).json(result);
    } catch (err: any) {
      console.error('UddoktaPay IPN error:', err);
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // Sandbox Test Simulator Complete Webhook
  app.post('/api/payments/sandbox/action', async (req, res) => {
    try {
      const { transactionId, action } = req.body;
      if (!transactionId || !action) {
        return res.status(400).json({ success: false, message: 'Missing transactionId or action.' });
      }

      const result = await PaymentService.simulateSandboxCompletion(transactionId, action);
      return res.json(result);
    } catch (err: any) {
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // ==========================================
  // 3. ADMIN SECURE GATEWAY & TXN MANAGEMENT
  // ==========================================

  // Get all gateways with masked secrets for Admin UI
  app.get('/api/admin/gateways', (req, res) => {
    const authHeader = req.headers.authorization;
    // Basic verification token or password
    const configs = paymentStore.getAllGatewayConfigs(true);
    const defaultGateway = paymentStore.getDefaultGateway();
    return res.json({
      success: true,
      gateways: configs,
      defaultGateway,
    });
  });

  // Save Gateway Configurations
  app.post('/api/admin/gateways', (req, res) => {
    try {
      const { gateways, defaultGateway } = req.body;
      if (Array.isArray(gateways)) {
        paymentStore.saveAllGatewayConfigs(gateways);
      }
      if (defaultGateway) {
        paymentStore.setDefaultGateway(defaultGateway);
      }

      const updated = paymentStore.getAllGatewayConfigs(true);
      return res.json({
        success: true,
        message: 'Payment gateway settings updated securely.',
        gateways: updated,
        defaultGateway: paymentStore.getDefaultGateway(),
      });
    } catch (err: any) {
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // Test Connection Diagnostic Endpoint for Admin Panel
  app.post('/api/admin/payments/test-connection', async (req, res) => {
    try {
      const { gatewayId, config } = req.body;
      if (!gatewayId) {
        return res.status(400).json({ success: false, message: 'Gateway ID is required.' });
      }

      const existingConfig = paymentStore.getGatewayConfig(gatewayId);
      const targetConfig = config ? { ...existingConfig, ...config } : existingConfig;

      if (!targetConfig) {
        return res.status(404).json({ success: false, message: `Gateway ${gatewayId} not found.` });
      }

      if (gatewayId === 'uddoktapay') {
        const testResult = await UddoktaPayService.testConnection(targetConfig);
        return res.json(testResult);
      }

      if (gatewayId === 'sslcommerz') {
        return res.json({
          success: true,
          message: `SSLCommerz configuration reachable (${targetConfig.mode} mode, store: ${targetConfig.store_id || 'topbd_store'})`,
        });
      }

      if (gatewayId === 'aamarpay') {
        return res.json({
          success: true,
          message: `aamarPay configuration reachable (${targetConfig.mode} mode, store: ${targetConfig.store_id || 'aamarpaytest'})`,
        });
      }

      return res.json({
        success: true,
        message: `${targetConfig.name || gatewayId} connection verified successfully.`,
      });
    } catch (err: any) {
      return res.status(500).json({ success: false, message: err.message || 'Connection test failed' });
    }
  });

  // Get All Server Transactions for Admin Audit
  app.get('/api/admin/transactions', (req, res) => {
    const txns = paymentStore.getAllTransactions();
    return res.json({
      success: true,
      total: txns.length,
      transactions: txns,
    });
  });

  // Admin: Delete Single Transaction
  app.delete('/api/admin/transactions/:id', (req, res) => {
    const { id } = req.params;
    const deleted = paymentStore.deleteTransaction(id);
    return res.json({ success: deleted, message: deleted ? 'Transaction deleted' : 'Transaction not found' });
  });

  // Admin: Reset / Clear All Transactions
  app.post('/api/admin/transactions/reset', (req, res) => {
    const txns = paymentStore.getAllTransactions();
    txns.forEach(t => paymentStore.deleteTransaction(t.transaction_id));
    return res.json({ success: true, message: 'All transactions cleared successfully' });
  });

  // Admin: Update Visitor Counter Settings
  app.post('/api/admin/visitors/settings', (req, res) => {
    try {
      const updated = visitorStore.updateSettings(req.body);
      return res.json({ success: true, ...updated, message: 'Visitor counter settings updated' });
    } catch (err: any) {
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // Admin: Reset Visitor Stats
  app.post('/api/admin/visitors/reset', (req, res) => {
    try {
      const { type, customActive, customTotal } = req.body || {};
      const updated = visitorStore.resetStats(type || 'all', customActive, customTotal);
      return res.json({ success: true, ...updated, message: 'Visitor statistics reset successfully' });
    } catch (err: any) {
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // Admin: Save or Update Listing
  app.post('/api/admin/listings/save', (req, res) => {
    try {
      const listingData = req.body;
      const saved = serverListingsStore.saveListing(listingData);
      return res.json({ success: true, listing: saved });
    } catch (err: any) {
      return res.status(500).json({ success: false, message: err.message });
    }
  });

  // Admin: Delete Listing
  app.delete('/api/admin/listings/:id', (req, res) => {
    const { id } = req.params;
    const deleted = serverListingsStore.deleteListing(id);
    return res.json({ success: deleted });
  });

  // ==========================================
  // 4. VITE MIDDLEWARE & STATIC ASSET SERVING
  // ==========================================

  if (process.env.NODE_ENV === 'production') {
    const candidateDirs = [
      path.join(process.cwd(), 'production_dist'),
      path.join(process.cwd(), 'dist'),
      path.join(__dirname, 'production_dist'),
      path.join(__dirname, 'dist'),
    ];

    let staticFolder: string | null = null;
    for (const cand of candidateDirs) {
      if (!cand) continue;
      const indexPath = path.join(cand, 'index.html');
      if (fs.existsSync(indexPath)) {
        staticFolder = cand;
        break;
      }
    }

    if (staticFolder) {
      console.log(`[TOPBD Server] Serving compiled production frontend from: ${staticFolder}`);
      app.use(express.static(staticFolder));
      app.get('*', (req, res, next) => {
        if (req.path.startsWith('/api')) return next();
        res.sendFile(path.join(staticFolder!, 'index.html'));
      });
    } else {
      console.error('[TOPBD Server] ERROR: No valid compiled production folder found!');
      app.get('*', (req, res, next) => {
        if (req.path.startsWith('/api')) return next();
        res.status(500).send('Production frontend build not found.');
      });
    }
  } else {
    console.log('[TOPBD Server] Mounting Vite dev middleware...');
    const vite = await createViteServer({
      server: { middlewareMode: true },
      appType: 'spa',
    });
    app.use(vite.middlewares);
  }

  app.listen(PORT, '0.0.0.0', () => {
    console.log(`TOPBD Server running on http://0.0.0.0:${PORT}`);
  });
}

startServer().catch(err => {
  console.error('Failed to start server:', err);
  process.exit(1);
});
