import type { Connect } from 'vite';
import crypto from 'crypto';
import fs from 'fs';
import { insertRawLead, getAllRawLeads, clearAllLeads, getSqliteBinaryPath } from './sqliteDb';

interface CAPIEventRecord {
  id: string;
  timestamp: string;
  eventName: string;
  eventId: string;
  status: 'sent_to_meta' | 'simulated_success' | 'failed';
  matchedParameters: string[];
  eventMatchQuality: number;
  rawPayload: any;
  metaResponse?: any;
  error?: string;
}

const recentEvents: CAPIEventRecord[] = [];

function hashMetaField(value?: string): string | undefined {
  if (!value) return undefined;
  const normalized = value.trim().toLowerCase();
  if (!normalized) return undefined;
  return crypto.createHash('sha256').update(normalized).digest('hex');
}

function hashPhone(phone?: string): string | undefined {
  if (!phone) return undefined;
  const digitsOnly = phone.replace(/\D/g, '');
  if (!digitsOnly) return undefined;
  return crypto.createHash('sha256').update(digitsOnly).digest('hex');
}

function calculateEstimatedEMQ(userData: Record<string, any>): { score: number; matched: string[] } {
  const matched: string[] = [];
  let score = 0;

  if (userData.em && userData.em.length > 0) {
    score += 3.5;
    matched.push('Email (em, hashed)');
  }
  if (userData.ph && userData.ph.length > 0) {
    score += 2.5;
    matched.push('Téléphone (ph, hashed)');
  }
  if (userData.fn && userData.fn.length > 0) {
    score += 0.8;
    matched.push('Prénom (fn, hashed)');
  }
  if (userData.ln && userData.ln.length > 0) {
    score += 0.5;
    matched.push('Nom (ln, hashed)');
  }
  if (userData.client_ip_address) {
    score += 1.0;
    matched.push('Adresse IP client');
  }
  if (userData.client_user_agent) {
    score += 0.5;
    matched.push('User Agent');
  }
  if (userData.fbc) {
    score += 0.5;
    matched.push('Meta Click ID (_fbc)');
  }
  if (userData.fbp) {
    score += 0.4;
    matched.push('Meta Browser ID (_fbp)');
  }

  return {
    score: Math.min(10, Math.round(score * 10) / 10),
    matched,
  };
}

export function createMetaApiMiddleware(): Connect.NextHandleFunction {
  return async (req, res, next) => {
    const url = req.url || '';

    // Route: GET /api/health
    if (url === '/api/health' && req.method === 'GET') {
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ status: 'ok', timestamp: new Date().toISOString() }));
      return;
    }

    // Route: GET /api/meta-events
    if (url === '/api/meta-events' && req.method === 'GET') {
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ events: recentEvents }));
      return;
    }

    // Route: DELETE /api/meta-events
    if (url === '/api/meta-events' && req.method === 'DELETE') {
      recentEvents.length = 0;
      res.setHeader('Content-Type', 'application/json');
      res.end(JSON.stringify({ success: true }));
      return;
    }

    // Route: GET /api/leads - Récupérer tous les leads non-hachés depuis SQLite
    if (url.startsWith('/api/leads') && req.method === 'GET' && !url.includes('/download-sqlite') && !url.includes('/export-csv')) {
      try {
        const leads = await getAllRawLeads();
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ success: true, count: leads.length, leads }));
      } catch (err: any) {
        res.statusCode = 500;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ success: false, error: err.message }));
      }
      return;
    }

    // Route: DELETE /api/leads - Vider la table SQLite des leads
    if (url === '/api/leads' && req.method === 'DELETE') {
      try {
        await clearAllLeads();
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ success: true }));
      } catch (err: any) {
        res.statusCode = 500;
        res.setHeader('Content-Type', 'application/json');
        res.end(JSON.stringify({ success: false, error: err.message }));
      }
      return;
    }

    // Route: GET /api/leads/download-sqlite - Télécharger directement le fichier binaire SQLite
    if (url.startsWith('/api/leads/download-sqlite') && req.method === 'GET') {
      try {
        // Ensure db is loaded and saved
        await getAllRawLeads();
        const dbPath = getSqliteBinaryPath();
        if (fs.existsSync(dbPath)) {
          const fileBuffer = fs.readFileSync(dbPath);
          res.setHeader('Content-Type', 'application/x-sqlite3');
          res.setHeader('Content-Disposition', 'attachment; filename="leads.sqlite"');
          res.end(fileBuffer);
        } else {
          res.statusCode = 404;
          res.end('Fichier SQLite non trouvé');
        }
      } catch (err: any) {
        res.statusCode = 500;
        res.end('Erreur lors du téléchargement SQLite: ' + err.message);
      }
      return;
    }

    // Route: GET /api/leads/export-csv - Exporter les leads bruts en CSV
    if (url.startsWith('/api/leads/export-csv') && req.method === 'GET') {
      try {
        const leads = await getAllRawLeads();
        const headers = [
          'ID', 'Date', 'Event ID', 'Prénom', 'Nom', 'Email', 'Téléphone',
          'Objectif', 'Frein', 'Niveau', 'fbclid', '_fbc', '_fbp',
          'utm_source', 'utm_medium', 'utm_campaign', 'IP', 'User Agent', 'Score EMQ'
        ];

        const rows = leads.map(l => [
          l.id,
          `"${(l.created_at || '').replace(/"/g, '""')}"`,
          `"${(l.event_id || '').replace(/"/g, '""')}"`,
          `"${(l.first_name || '').replace(/"/g, '""')}"`,
          `"${(l.last_name || '').replace(/"/g, '""')}"`,
          `"${(l.email || '').replace(/"/g, '""')}"`,
          `"${(l.phone || '').replace(/"/g, '""')}"`,
          `"${(l.goal || '').replace(/"/g, '""')}"`,
          `"${(l.blocker || '').replace(/"/g, '""')}"`,
          `"${(l.current_level || '').replace(/"/g, '""')}"`,
          `"${(l.fbclid || '').replace(/"/g, '""')}"`,
          `"${(l.fbc || '').replace(/"/g, '""')}"`,
          `"${(l.fbp || '').replace(/"/g, '""')}"`,
          `"${(l.utm_source || '').replace(/"/g, '""')}"`,
          `"${(l.utm_medium || '').replace(/"/g, '""')}"`,
          `"${(l.utm_campaign || '').replace(/"/g, '""')}"`,
          `"${(l.ip_address || '').replace(/"/g, '""')}"`,
          `"${(l.user_agent || '').replace(/"/g, '""')}"`,
          l.emq_score || 0
        ]);

        const csvContent = '\uFEFF' + [headers.join(','), ...rows.map(r => r.join(','))].join('\r\n');
        res.setHeader('Content-Type', 'text/csv; charset=utf-8');
        res.setHeader('Content-Disposition', 'attachment; filename="leads_export.csv"');
        res.end(csvContent);
      } catch (err: any) {
        res.statusCode = 500;
        res.end('Erreur export CSV: ' + err.message);
      }
      return;
    }

    // Route: POST /api/meta-capi
    if (url === '/api/meta-capi' && req.method === 'POST') {
      let body = '';
      req.on('data', (chunk) => {
        body += chunk;
      });

      req.on('end', async () => {
        try {
          const parsed = JSON.parse(body || '{}');
          const {
            userData = {},
            trackingData = {},
            assessmentData = {},
            eventName = 'Lead',
            eventId = `lead_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`,
          } = parsed;

          const forwarded = req.headers['x-forwarded-for'];
          let clientIp = typeof forwarded === 'string' ? forwarded.split(',')[0].trim() : req.socket.remoteAddress || '127.0.0.1';
          if (clientIp.startsWith('::ffff:')) clientIp = clientIp.substring(7);
          const clientUserAgent = (req.headers['user-agent'] as string) || trackingData.userAgent || 'Mozilla/5.0';

          const hashedEmail = hashMetaField(userData.email);
          const hashedPhone = hashPhone(userData.phone);
          const hashedFirstName = hashMetaField(userData.firstName);
          const hashedLastName = hashMetaField(userData.lastName);

          let fbc = trackingData.fbc;
          if (!fbc && trackingData.fbclid) {
            fbc = `fb.1.${Date.now()}.${trackingData.fbclid}`;
          }
          const fbp = trackingData.fbp || `fb.1.${Date.now()}.${Math.floor(Math.random() * 9000000000) + 1000000000}`;

          const metaUserData: Record<string, any> = {
            client_ip_address: clientIp,
            client_user_agent: clientUserAgent,
            fbc: fbc || undefined,
            fbp: fbp || undefined,
            country: [hashMetaField('fr')],
          };

          if (hashedEmail) metaUserData.em = [hashedEmail];
          if (hashedPhone) metaUserData.ph = [hashedPhone];
          if (hashedFirstName) metaUserData.fn = [hashedFirstName];
          if (hashedLastName) metaUserData.ln = [hashedLastName];

          const customData: Record<string, any> = {
            content_name: "Test d'Anglais Gratuit (Mobile Ads)",
            content_category: 'Language Assessment',
            currency: 'EUR',
            value: 0,
            english_goal: assessmentData.goal,
            primary_blocker: assessmentData.blocker,
            current_level: assessmentData.currentLevel,
            fbclid: trackingData.fbclid || undefined,
            utm_source: trackingData.utm_source || undefined,
            utm_campaign: trackingData.utm_campaign || undefined,
            utm_medium: trackingData.utm_medium || undefined,
          };

          const eventPayload = {
            data: [
              {
                event_name: eventName,
                event_time: Math.floor(Date.now() / 1000),
                event_id: eventId,
                event_source_url: trackingData.pageUrl || 'https://example.com/test-anglais',
                action_source: 'website',
                user_data: metaUserData,
                custom_data: customData,
              },
            ],
          };

          const { score: emqScore, matched: matchedParams } = calculateEstimatedEMQ(metaUserData);

          // =========================================================================
          // ENREGISTREMENT DES DONNÉES BRUTES NON-HACHÉES DANS SQLITE (leads.sqlite)
          // =========================================================================
          let sqliteInsertedId = null;
          try {
            sqliteInsertedId = await insertRawLead({
              event_id: eventId,
              created_at: new Date().toISOString(),
              first_name: userData.firstName || '',
              last_name: userData.lastName || '',
              email: userData.email || '',
              phone: userData.phone || '',
              goal: assessmentData.goal || '',
              blocker: assessmentData.blocker || '',
              current_level: assessmentData.currentLevel || '',
              fbclid: trackingData.fbclid || '',
              fbc: fbc || '',
              fbp: fbp || '',
              utm_source: trackingData.utm_source || '',
              utm_medium: trackingData.utm_medium || '',
              utm_campaign: trackingData.utm_campaign || '',
              utm_content: trackingData.utm_content || '',
              utm_term: trackingData.utm_term || '',
              ip_address: clientIp,
              user_agent: clientUserAgent,
              page_url: trackingData.pageUrl || '',
              emq_score: emqScore,
              raw_json: JSON.stringify(parsed),
            });
          } catch (dbErr) {
            console.error('Erreur insertion SQLite:', dbErr);
          }

          const pixelId = process.env.META_PIXEL_ID;
          const accessToken = process.env.META_CAPI_ACCESS_TOKEN;

          let dispatchResult: any;
          let eventStatus: 'sent_to_meta' | 'simulated_success' | 'failed' = 'simulated_success';
          let errorMessage: string | undefined;

          if (pixelId && accessToken) {
            try {
              const metaUrl = `https://graph.facebook.com/v19.0/${pixelId}/events?access_token=${accessToken}`;
              const metaResponse = await fetch(metaUrl, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(eventPayload),
              });
              dispatchResult = await metaResponse.json();
              if (metaResponse.ok && dispatchResult.events_received) {
                eventStatus = 'sent_to_meta';
              } else {
                eventStatus = 'failed';
                errorMessage = dispatchResult?.error?.message || 'Meta API returned error';
              }
            } catch (err: any) {
              eventStatus = 'failed';
              errorMessage = err.message;
              dispatchResult = { error: errorMessage };
            }
          } else {
            dispatchResult = {
              events_received: 1,
              messages: [],
              fbtrace_id: `trace_${Math.random().toString(36).substring(2, 12)}`,
              note: 'Simulation CAPI active (prêt pour Meta Pixel & Access Token)',
            };
            eventStatus = 'simulated_success';
          }

          const record: CAPIEventRecord = {
            id: `ev_${Date.now()}`,
            timestamp: new Date().toLocaleTimeString('fr-FR'),
            eventName,
            eventId,
            status: eventStatus,
            matchedParameters: matchedParams,
            eventMatchQuality: emqScore,
            rawPayload: eventPayload,
            metaResponse: dispatchResult,
            error: errorMessage,
          };

          recentEvents.unshift(record);
          if (recentEvents.length > 30) recentEvents.pop();

          res.setHeader('Content-Type', 'application/json');
          res.end(
            JSON.stringify({
              success: eventStatus !== 'failed',
              status: eventStatus,
              eventId,
              emqScore,
              sqliteId: sqliteInsertedId,
              matchedParameters: matchedParams,
              metaResponse: dispatchResult,
              error: errorMessage,
            })
          );
        } catch (err: any) {
          res.statusCode = 500;
          res.setHeader('Content-Type', 'application/json');
          res.end(JSON.stringify({ success: false, error: err.message }));
        }
      });
      return;
    }

    next();
  };
}
