import { randomUUID } from 'crypto';
import { Router, Request, Response } from 'express';
import pool from '../db';

const router = Router();

type GoRouteRow = {
  slug: string;
  active: boolean;
  source: string | null;
  campaign: string | null;
  creative: string | null;
  ad_type: string | null;
  default_destination_path: string | null;
};

type GoExperimentRow = {
  id: string;
  slug: string;
  name: string;
  traffic_source: string | null;
  creative: string | null;
  ad_type: string | null;
};

type GoVariantRow = {
  id: string;
  experiment_id: string;
  variant_key: string;
  destination_path: string;
  weight: number;
};

type ResolvedTrafficRoute = {
  click_id: string;
  slug: string;
  source: string;
  campaign: string;
  creative: string;
  ad_type: string | null;
  experiment: { id: string; name: string } | null;
  variant: string;
  destination_path: string;
  destination_url: string;
};

function getClientIp(req: Request): string | null {
  const forwarded = req.headers['x-rm-client-ip']
    || req.headers['x-forwarded-for']
    || req.headers['cf-connecting-ip'];

  if (typeof forwarded === 'string' && forwarded.trim()) {
    return forwarded.split(',')[0]?.trim() || null;
  }

  return req.ip || req.socket.remoteAddress || null;
}

function normalizePath(path: string): string {
  if (/^https?:\/\//i.test(path)) return path;
  return path.startsWith('/') ? path : `/${path}`;
}

function chooseWeightedVariant(variants: GoVariantRow[]): GoVariantRow {
  const totalWeight = variants.reduce((sum, variant) => sum + Math.max(variant.weight || 0, 0), 0);
  if (totalWeight <= 0) return variants[0];

  let cursor = Math.random() * totalWeight;
  for (const variant of variants) {
    cursor -= Math.max(variant.weight || 0, 0);
    if (cursor <= 0) return variant;
  }

  return variants[variants.length - 1];
}

async function resolveTrafficRoute(req: Request): Promise<ResolvedTrafficRoute | null> {
  const slug = String(req.params.slug || '').trim().toLowerCase();
  if (!slug) {
    return null;
  }

  const routeResult = await pool.query<GoRouteRow>(
    `SELECT slug, active, source, campaign, creative, ad_type, default_destination_path
     FROM rm_go_routes
     WHERE slug = $1 AND active = TRUE
     LIMIT 1`,
    [slug]
  );

  const route = routeResult.rows[0];
  if (!route) {
    return null;
  }

  const experimentResult = await pool.query<GoExperimentRow>(
    `SELECT id, slug, name, traffic_source, creative, ad_type
     FROM rm_go_experiments
     WHERE slug = $1
       AND active = TRUE
       AND (start_at IS NULL OR start_at <= NOW())
       AND (end_at IS NULL OR end_at >= NOW())
     ORDER BY updated_at DESC, created_at DESC
     LIMIT 1`,
    [slug]
  );

  const experiment = experimentResult.rows[0] || null;

  let variant: GoVariantRow | null = null;
  if (experiment) {
    const variantResult = await pool.query<GoVariantRow>(
      `SELECT id, experiment_id, variant_key, destination_path, weight
       FROM rm_go_variants
       WHERE experiment_id = $1
         AND active = TRUE
         AND weight > 0
       ORDER BY variant_key ASC`,
      [experiment.id]
    );

    if (variantResult.rows.length > 0) {
      variant = chooseWeightedVariant(variantResult.rows);
    }
  }

  const destinationPath = normalizePath(
    variant?.destination_path
    || route.default_destination_path
    || '/'
  );

  const frontendBase = process.env.FRONTEND_URL || 'https://rainmakersports.app';
  const destinationUrl = new URL(destinationPath, frontendBase);

  const source = route.source || experiment?.traffic_source || String(req.query.src || req.query.utm_source || 'direct');
  const campaign = route.campaign || String(req.query.campaign || req.query.utm_campaign || slug);
  const creative = route.creative || experiment?.creative || String(req.query.creative || req.query.utm_content || slug);
  const adType = route.ad_type || experiment?.ad_type || (typeof req.query.ad_type === 'string' ? req.query.ad_type : null);
  const clickId = randomUUID();
  const assignedVariant = variant?.variant_key || 'default';

  for (const [key, rawValue] of Object.entries(req.query)) {
    if (rawValue == null) continue;
    if (Array.isArray(rawValue)) {
      for (const item of rawValue) {
        destinationUrl.searchParams.append(key, String(item));
      }
    } else {
      destinationUrl.searchParams.set(key, String(rawValue));
    }
  }

  destinationUrl.searchParams.set('src', source);
  destinationUrl.searchParams.set('campaign', campaign);
  destinationUrl.searchParams.set('creative', creative);
  destinationUrl.searchParams.set('variant', assignedVariant);
  destinationUrl.searchParams.set('click_id', clickId);
  destinationUrl.searchParams.set('slug', slug);

  if (experiment?.name) {
    destinationUrl.searchParams.set('exp', experiment.name);
  }

  if (adType) {
    destinationUrl.searchParams.set('ad_type', adType);
  }

  if (!destinationUrl.searchParams.get('utm_source')) {
    destinationUrl.searchParams.set('utm_source', source);
  }
  if (!destinationUrl.searchParams.get('utm_medium')) {
    destinationUrl.searchParams.set('utm_medium', 'paid');
  }
  if (!destinationUrl.searchParams.get('utm_campaign')) {
    destinationUrl.searchParams.set('utm_campaign', campaign);
  }
  if (!destinationUrl.searchParams.get('utm_content')) {
    destinationUrl.searchParams.set('utm_content', creative);
  }

  const referrer = (req.headers.referer || req.headers.referrer || '') as string;
  const userAgent = String(req.headers['user-agent'] || '').slice(0, 512) || null;
  const ip = getClientIp(req);

  await pool.query(
    `INSERT INTO rm_go_clicks
       (click_id, slug, experiment_id, variant_id, source, campaign, creative, ad_type,
        assigned_variant, destination_path, destination_url, referrer, ip_address,
        user_agent, query_string, query_params)
     VALUES
       ($1, $2, $3, $4, $5, $6, $7, $8,
        $9, $10, $11, $12, $13,
        $14, $15, $16)`,
    [
      clickId,
      slug,
      experiment?.id || null,
      variant?.id || null,
      source,
      campaign,
      creative,
      adType,
      assignedVariant,
      destinationPath,
      destinationUrl.toString(),
      referrer || null,
      ip,
      userAgent,
      req.originalUrl.split('?')[1] || null,
      JSON.stringify(req.query || {}),
    ]
  );

  return {
    click_id: clickId,
    slug,
    source,
    campaign,
    creative,
    ad_type: adType,
    experiment: experiment ? {
      id: experiment.id,
      name: experiment.name,
    } : null,
    variant: assignedVariant,
    destination_path: destinationPath,
    destination_url: destinationUrl.toString(),
  };
}

router.get('/resolve/:slug', async (req: Request, res: Response) => {
  try {
    const resolved = await resolveTrafficRoute(req);
    if (!resolved) {
      res.status(404).json({ error: 'Unknown or inactive go slug' });
      return;
    }

    res.json({
      ok: true,
      ...resolved,
    });
  } catch (err) {
    console.error('Traffic resolve error:', err);
    res.status(500).json({ error: 'Failed to resolve traffic route' });
  }
});

router.get('/redirect/:slug', async (req: Request, res: Response) => {
  try {
    const resolved = await resolveTrafficRoute(req);
    if (!resolved) {
      res.redirect(307, process.env.FRONTEND_URL || 'https://rainmakersports.app');
      return;
    }

    const cookieOptions = {
      maxAge: 1000 * 60 * 60 * 24 * 30,
      sameSite: 'lax' as const,
      secure: true,
      path: '/',
    };

    res.cookie('rm_click_id', resolved.click_id, cookieOptions);
    res.cookie('rm_click_src', resolved.source, cookieOptions);
    res.cookie('rm_click_campaign', resolved.campaign, cookieOptions);
    res.cookie('rm_click_creative', resolved.creative, cookieOptions);
    res.cookie('rm_click_variant', resolved.variant, cookieOptions);
    res.cookie('rm_click_slug', resolved.slug, cookieOptions);
    if (resolved.experiment?.name) {
      res.cookie('rm_click_exp', resolved.experiment.name, cookieOptions);
    }
    if (resolved.ad_type) {
      res.cookie('rm_click_ad_type', resolved.ad_type, cookieOptions);
    }

    res.redirect(307, resolved.destination_url);
  } catch (err) {
    console.error('Traffic redirect error:', err);
    res.redirect(307, process.env.FRONTEND_URL || 'https://rainmakersports.app');
  }
});

export default router;
