import { UAParser } from "ua-parser-js";
import { checkIpReputation } from "./ip-reputation";
import { getPartners } from "./data";

const BOT_USER_AGENT_KEYWORDS = [
  "googlebot",
  "adsbot-google",
  "bingbot",
  "slurp",
  "duckduckbot",
  "baiduspider",
  "yandexbot",
  "sogou",
  "exabot",
  "facebot",
  "ia_archiver",
];

// Google Ads parameter names to detect
const GOOGLE_ADS_PARAMS = [
  "gclid",
  "gad_source",
  "gad_campaignid",
  "gbraid",
  "wbraid",
  "gclsrc",
];

export function isBot(userAgent: string | null, visitorTypeHeader?: string | null) {
  if (visitorTypeHeader === "bot") return true;
  if (!userAgent) return true;
  const normalized = userAgent.toLowerCase();
  return BOT_USER_AGENT_KEYWORDS.some((keyword) => normalized.includes(keyword));
}

export function isMobileDevice(userAgent: string | null) {
  if (!userAgent) return false;
  const parser = new UAParser(userAgent);
  const deviceType = parser.getDevice().type;
  return deviceType === "mobile" || deviceType === "tablet";
}

/**
 * Checks if the user comes from Google Ads by detecting Google Ads parameters in the URL
 */
export function hasGoogleAdsParams(searchParams: SearchParams): boolean {
  return GOOGLE_ADS_PARAMS.some((param) => {
    const value = searchParams[param];
    return value !== undefined && value !== null && value !== "";
  });
}

/**
 * Checks if the referer indicates the user came from Google (any Google domain or Google Ads network)
 * This includes:
 * - Google Search (google.com/search)
 * - Google homepage (google.com/)
 * - Google Ads network (googleads.g.doubleclick.net)
 * - Any Google domain (google.co.uk, google.fr, etc.)
 * 
 * When users click Google Ads, the referer can be from various Google sources, not just search
 */
export function isFromGoogle(referer: string | null): boolean {
  if (!referer) return false;
  
  const refererLower = referer.toLowerCase();
  
  // Check for Google Ads network domains
  if (refererLower.includes("googleads.g.doubleclick.net") || 
      refererLower.includes("googleadservices.com") ||
      refererLower.includes("googlesyndication.com") ||
      refererLower.includes("doubleclick.net")) {
    return true;
  }
  
  // Check if it's any Google domain
  if (refererLower.includes("google")) {
    try {
      const refererUrl = new URL(referer);
      const hostname = refererUrl.hostname.toLowerCase();
      
      // Check if hostname is a Google domain (supports all country-specific domains)
      // Examples: google.com, www.google.com, google.co.uk, google.fr, google.de, google.com.au, etc.
      const isGoogleHost = hostname === "google.com" || 
                          hostname === "www.google.com" ||
                          hostname.endsWith(".google.com") ||
                          /^google\.(co\.|com\.)?[a-z]{2,3}(\.[a-z]{2})?$/.test(hostname) || // google.co.uk, google.com.au
                          /^www\.google\.(co\.|com\.)?[a-z]{2,3}(\.[a-z]{2})?$/.test(hostname); // www.google.co.uk
      
      return isGoogleHost;
    } catch {
      // If referer is not a valid URL, check if it contains "google"
      return refererLower.includes("google");
    }
  }
  
  return false;
}

import type { SearchParams } from "@/types/data";

interface ShouldShowUnlicensedPartnersArgs {
  readonly userAgent: string | null;
  readonly visitorTypeHeader?: string | null;
  readonly searchParams: SearchParams;
  readonly referer: string | null;
  readonly secChUaMobile?: string | null;
  readonly clientIp?: string | null;
}

/**
 * Helper to safely extract string value from searchParams
 */
function getParamValue(value: string | string[] | undefined): string {
  if (!value) return "";
  if (Array.isArray(value)) return value[0] || "";
  return String(value);
}

/**
 * Validates URL parameters for Google Ads
 * Rule: Must have gclid. If it is missing, reflect only licensed brands
 */
function validateGoogleAdsUrl(searchParams: SearchParams): boolean {
  const gclid = getParamValue(searchParams.gclid);
  return gclid !== "";
}

/**
 * Checks if device is mobile using multi-layered approach
 * Primary: Sec-CH-UA-Mobile header (must be "?1" to be mobile)
 * Fallback: User-Agent header keywords (Android, iPhone, iPad, iPod, Mobile, BlackBerry)
 */
function isMobileDeviceMultiLayer(
  userAgent: string | null,
  secChUaMobile: string | null | undefined
): boolean {
  // Primary check: Sec-CH-UA-Mobile header
  if (secChUaMobile !== undefined && secChUaMobile !== null) {
    // If header exists and value is "?1", it's mobile
    // If header exists and value is NOT "?1", it's NOT mobile
    return secChUaMobile === "?1";
  }
  
  // Fallback: Check User-Agent header
  if (!userAgent) return false;
  
  const userAgentLower = userAgent.toLowerCase();
  const mobileKeywords = ["android", "iphone", "ipad", "ipod", "mobile", "blackberry"];
  
  return mobileKeywords.some((keyword) => userAgentLower.includes(keyword));
}

/**
 * Checks IP reputation - returns true if IP is safe (not datacenter/hosting/BOT)
 * Uses the IP reputation service (see ip-reputation.ts for integration)
 * 
 * @param clientIp - The client IP address
 * @returns true if IP is safe (residential/user), false if datacenter/hosting/BOT
 */
async function isIpSafe(clientIp: string | null): Promise<boolean> {
  if (!clientIp) return false;
  
  const reputation = await checkIpReputation(clientIp);
  return reputation.isSafe;
}

/**
 * Checks if there are any unlicensed partners in the partners.json file
 * If there are no unlicensed partners, the logic should be disabled
 */
function hasUnlicensedPartners(): boolean {
  try {
    const partners = getPartners();
    return partners.some((partner) => !partner.licensed);
  } catch {
    // If we can't read partners, default to showing only licensed (safer)
    return false;
  }
}

/**
 * Checks if unlicensed partners should be shown
 * 
 * RULE: Show ONLY licensed brands if referer is NOT google
 * 
 * RULE: Show ONLY unlicensed partners if ALL 4 conditions are TRUE:
 * 1. Referer: User's referer is google
 * 2. URL Validation: Request contains gclid
 * 3. Device Verification: Device is mobile (Sec-CH-UA-Mobile header OR User-Agent keywords)
 * 4. IP Reputation: IP is safe (not datacenter/hosting/BOT)
 * 5. Not a BOT: User is not a bot
 * 
 * If ANY condition is NOT met, show ONLY licensed partners
 * Bots ALWAYS see licensed partners only (never unlicensed)
 * 
 * IMPORTANT: If partners.json ONLY has licensed brands, this logic is DISABLED
 * and will always return false (show only licensed partners)
 */
export async function shouldShowUnlicensedPartners({
  userAgent,
  visitorTypeHeader,
  searchParams,
  referer,
  secChUaMobile,
  clientIp,
}: ShouldShowUnlicensedPartnersArgs): Promise<boolean> {
  // If there are no unlicensed partners in partners.json, disable the logic
  // Always show only licensed partners
  if (!hasUnlicensedPartners()) {
    return false;
  }
  
  // If referer is NOT google, show only licensed brands
  if (!isFromGoogle(referer)) {
    return false;
  }
  
  // Bots ALWAYS see licensed partners only - never unlicensed
  if (isBot(userAgent, visitorTypeHeader)) {
    return false;
  }
  
  // Condition 1: URL Validation
  // Must have gclid. If it is missing, reflect only licensed brands
  const isValidUrl = validateGoogleAdsUrl(searchParams);
  if (!isValidUrl) {
    return false;
  }
  
  // Condition 2: Device Verification (multi-layered)
  // Primary: Sec-CH-UA-Mobile header, Fallback: User-Agent keywords
  const isMobile = isMobileDeviceMultiLayer(userAgent, secChUaMobile);
  if (!isMobile) {
    return false;
  }
  
  // Condition 3: IP Reputation
  // IP must be safe (not datacenter/hosting/BOT)
  const isIpSafeResult = await isIpSafe(clientIp || null);
  if (!isIpSafeResult) {
    return false;
  }
  
  // All conditions met - show unlicensed partners
  return true;
}
