<?php
// api/reports.php — Reportes mensuales con ejecuciones, estrategias y resultados
header('Content-Type: application/json');
require_once __DIR__ . '/../config.php';
require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../auth.php';
require_once __DIR__ . '/../credentials.php';
require_once __DIR__ . '/google-auth.php';
require_once __DIR__ . '/logger.php';
dm_require_login();

$input     = json_decode(file_get_contents('php://input'), true) ?? [];
$action    = $_GET['action'] ?? $input['action'] ?? 'generate';
$client_id = (int)($input['client_id'] ?? $_GET['client_id'] ?? 0);

if (!$client_id) { echo json_encode(['ok'=>false,'error'=>'client_id requerido']); exit; }
dm_require_client_access($client_id);

// CSRF solo en acciones de escritura
if ($action === 'generate') dm_csrf_verify();

// ── Helpers ───────────────────────────────────────────────────────────────────

function rfmt(float $v): string {
    if ($v >= 1000000) return '$'.number_format($v/1000000,1,',','.').'M';
    if ($v >= 1000)    return '$'.number_format($v/1000,0,',','.').'K';
    return '$'.number_format($v,0,',','.');
}
function rnum(float $v, int $d=0): string { return number_format($v,$d,',','.'); }

function meta_r(string $ep, array $p, string $tok): array {
    $p['access_token']=$tok;
    $ch=curl_init("https://graph.facebook.com/v19.0/{$ep}?".http_build_query($p));
    curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_TIMEOUT=>25,CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2]);
    $r=json_decode(curl_exec($ch),true); curl_close($ch); return $r??[];
}

function gads_r(string $gaql, string $cid, string $access, string $dev_tok, string $mcc_id=''): array {
    $headers=['Authorization: Bearer '.$access,'developer-token: '.$dev_tok,'Content-Type: application/json'];
    if($mcc_id && $mcc_id!==$cid) $headers[]='login-customer-id: '.preg_replace('/[^0-9]/','', $mcc_id);
    $ch=curl_init("https://googleads.googleapis.com/v22/customers/{$cid}/googleAds:searchStream");
    curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,CURLOPT_TIMEOUT=>25,CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2,
        CURLOPT_HTTPHEADER=>$headers,
        CURLOPT_POSTFIELDS=>json_encode(['query'=>$gaql])]);
    $r=json_decode(curl_exec($ch),true); curl_close($ch); return $r??[];
}

// ── Compartir reporte (generar token público) ─────────────────────────────────
if ($action === 'share') {
    dm_csrf_verify();
    $report_id = (int)($input['id'] ?? 0);
    if (!$report_id) { echo json_encode(['ok'=>false,'error'=>'id requerido']); exit; }

    $check = $pdo->prepare("SELECT id FROM dm_reports WHERE id=? AND client_id=? LIMIT 1");
    $check->execute([$report_id, $client_id]);
    if (!$check->fetch()) { echo json_encode(['ok'=>false,'error'=>'Reporte no encontrado']); exit; }

    try {
        $pdo->exec("CREATE TABLE IF NOT EXISTS dm_report_tokens (
            id INT AUTO_INCREMENT PRIMARY KEY,
            report_id INT NOT NULL,
            client_id INT NOT NULL,
            token VARCHAR(64) NOT NULL UNIQUE,
            expires_at DATETIME NOT NULL,
            created_at DATETIME NOT NULL DEFAULT NOW(),
            INDEX idx_token (token),
            INDEX idx_report (report_id)
        ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4");

        $existing = $pdo->prepare("SELECT token FROM dm_report_tokens WHERE report_id=? AND expires_at > NOW() LIMIT 1");
        $existing->execute([$report_id]);
        $row = $existing->fetch(PDO::FETCH_ASSOC);

        if ($row) {
            $token = $row['token'];
        } else {
            $token = bin2hex(random_bytes(32));
            $expires = date('Y-m-d H:i:s', strtotime('+30 days'));
            $pdo->prepare("INSERT INTO dm_report_tokens (report_id, client_id, token, expires_at) VALUES (?,?,?,?)")
                ->execute([$report_id, $client_id, $token, $expires]);
        }

        $base = rtrim(defined('APP_URL') ? APP_URL : 'https://dimark.co/supercerebro', '/');
        echo json_encode(['ok'=>true,'url'=>$base.'/public-report.php?token='.$token]);
    } catch (Exception $e) {
        echo json_encode(['ok'=>false,'error'=>'Error al generar enlace']);
    }
    exit;
}

// ── Listar reportes ───────────────────────────────────────────────────────────
if ($action === 'list') {
    try {
        $rows = $pdo->prepare("SELECT id, period_label, DATE_FORMAT(created_at,'%d/%m/%Y') AS created_at FROM dm_reports WHERE client_id=? ORDER BY period_from DESC LIMIT 24");
        $rows->execute([$client_id]);
        echo json_encode(['ok'=>true,'reports'=>$rows->fetchAll(PDO::FETCH_ASSOC)]);
    } catch (Exception $e) {
        echo json_encode(['ok'=>true,'reports'=>[]]);
    }
    exit;
}

// ── Obtener reporte por ID ────────────────────────────────────────────────────
if ($action === 'get') {
    $id = (int)($_GET['id'] ?? 0);
    if (!$id) { echo json_encode(['ok'=>false,'error'=>'id requerido']); exit; }
    $row = $pdo->prepare("SELECT * FROM dm_reports WHERE id=? AND client_id=?");
    $row->execute([$id, $client_id]);
    $r = $row->fetch(PDO::FETCH_ASSOC);
    if (!$r) { echo json_encode(['ok'=>false,'error'=>'No encontrado']); exit; }
    echo json_encode(['ok'=>true,'html'=>$r['html'],'period_label'=>$r['period_label']]);
    exit;
}

// ── Servicios conectados del cliente ─────────────────────────────────────────
if ($action === 'services') {
    $meta_c   = dm_get_credentials($client_id, 'meta');
    $google_c = dm_get_credentials($client_id, 'google');
    $gsc_c    = dm_get_credentials($client_id, 'gsc');

    // Meta: access_token puede ser por cliente o vía META_SYSTEM_TOKEN global
    $meta_token = $meta_c['access_token'] ?? (defined('META_SYSTEM_TOKEN') ? META_SYSTEM_TOKEN : '');
    $meta_ok    = !empty($meta_token) && !empty($meta_c['ad_account_id']);

    // Google Ads: refresh_token y dev_token son constantes globales (nunca por cliente)
    $g_refresh  = defined('GOOGLE_REFRESH_TOKEN') ? GOOGLE_REFRESH_TOKEN : '';
    $g_customer = $google_c['customer_id'] ?? (defined('GOOGLE_CUSTOMER_ID') ? GOOGLE_CUSTOMER_ID : '');
    $g_dev      = defined('GOOGLE_DEV_TOKEN') ? GOOGLE_DEV_TOKEN : '';
    $google_ok  = !empty($g_refresh) && !empty($g_customer) && !empty($g_dev);

    // GSC: usa clave 'domain' (no 'site_url'), refresh_token también puede ser global
    $gsc_refresh = $gsc_c['refresh_token'] ?? (defined('GOOGLE_REFRESH_TOKEN') ? GOOGLE_REFRESH_TOKEN : '');
    $gsc_domain  = $gsc_c['domain'] ?? '';
    $gsc_ok      = !empty($gsc_refresh) && !empty($gsc_domain);

    echo json_encode(['ok'=>true,'services'=>[
        'meta'   => $meta_ok,
        'google' => $google_ok,
        'seo'    => $gsc_ok,
    ]]);
    exit;
}

// ── COMPARE — delta vs período anterior (usa dm_metrics_history) ─────────────
if ($action === 'compare') {
    $days_map = ['7d'=>7,'14d'=>14,'30d'=>30];
    $days     = $days_map[$input['period'] ?? $_GET['period'] ?? '30d'] ?? 30;
    $services = $input['services'] ?? ['meta','google','gsc'];

    $curr_from = date('Y-m-d', strtotime("-{$days} days"));
    $curr_to   = date('Y-m-d');
    $prev_from = date('Y-m-d', strtotime("-" . ($days * 2) . " days"));
    $prev_to   = date('Y-m-d', strtotime("-{$days} days - 1 day"));

    $svcs_map    = ['seo' => 'gsc'];  // alias: services usa 'seo', history usa 'gsc'
    $db_services = array_map(fn($s) => $svcs_map[$s] ?? $s, $services);
    $db_services = array_values(array_intersect($db_services, ['meta','google','gsc','tiktok'])); // whitelist
    if (empty($db_services)) {
        echo json_encode(['ok'=>true,'deltas'=>[],'has_data'=>false]); exit;
    }
    $ph = implode(',', array_fill(0, count($db_services), '?'));

    $stmt = $pdo->prepare(
        "SELECT service, metric_date, data FROM dm_metrics_history
          WHERE client_id = ? AND service IN ({$ph}) AND metric_date >= ?
          ORDER BY service, metric_date ASC"
    );
    $stmt->execute(array_merge([$client_id], $db_services, [$prev_from]));

    // Indexar por service → date → data
    $by_svc = [];
    foreach ($stmt->fetchAll(PDO::FETCH_ASSOC) as $row) {
        $by_svc[$row['service']][$row['metric_date']] = json_decode($row['data'], true);
    }

    function cmp_sum(array $svc_data, string $field, string $from, string $to): float {
        $total = 0.0;
        foreach ($svc_data as $date => $d) {
            if ($date >= $from && $date <= $to) $total += (float)($d[$field] ?? 0);
        }
        return $total;
    }
    function cmp_avg(array $svc_data, string $field, string $from, string $to): ?float {
        $vals = [];
        foreach ($svc_data as $date => $d) {
            if ($date >= $from && $date <= $to && isset($d[$field]) && $d[$field] !== null) {
                $vals[] = (float)$d[$field];
            }
        }
        return count($vals) > 0 ? array_sum($vals) / count($vals) : null;
    }
    function cmp_delta(float $curr, float $prev): array {
        $diff = $curr - $prev;
        $pct  = $prev > 0 ? round($diff / $prev * 100, 1) : ($curr > 0 ? 100.0 : 0.0);
        return ['curr' => round($curr, 1), 'prev' => round($prev, 1), 'diff' => round($diff, 1), 'pct' => $pct,
                'trend' => $pct > 5 ? 'up' : ($pct < -5 ? 'down' : 'stable')];
    }

    $deltas = [];

    if (isset($by_svc['meta'])) {
        $md = $by_svc['meta'];
        $deltas['meta'] = [
            'spend'       => cmp_delta(cmp_sum($md,'spend',$curr_from,$curr_to),       cmp_sum($md,'spend',$prev_from,$prev_to)),
            'clicks'      => cmp_delta(cmp_sum($md,'clicks',$curr_from,$curr_to),      cmp_sum($md,'clicks',$prev_from,$prev_to)),
            'impressions' => cmp_delta(cmp_sum($md,'impressions',$curr_from,$curr_to), cmp_sum($md,'impressions',$prev_from,$prev_to)),
            'conversions' => cmp_delta(cmp_sum($md,'conversions',$curr_from,$curr_to), cmp_sum($md,'conversions',$prev_from,$prev_to)),
        ];
    }
    if (isset($by_svc['google'])) {
        $gd = $by_svc['google'];
        $curr_is = cmp_avg($gd,'search_impression_share',$curr_from,$curr_to);
        $prev_is = cmp_avg($gd,'search_impression_share',$prev_from,$prev_to);
        $deltas['google'] = [
            'cost'                    => cmp_delta(cmp_sum($gd,'cost',$curr_from,$curr_to),         cmp_sum($gd,'cost',$prev_from,$prev_to)),
            'clicks'                  => cmp_delta(cmp_sum($gd,'clicks',$curr_from,$curr_to),       cmp_sum($gd,'clicks',$prev_from,$prev_to)),
            'conversions'             => cmp_delta(cmp_sum($gd,'conversions',$curr_from,$curr_to),  cmp_sum($gd,'conversions',$prev_from,$prev_to)),
            'search_impression_share' => $curr_is !== null
                ? cmp_delta($curr_is, $prev_is ?? 0.0)
                : null,
        ];
    }
    if (isset($by_svc['gsc'])) {
        $sd = $by_svc['gsc'];
        $deltas['seo'] = [
            'clicks'      => cmp_delta(cmp_sum($sd,'clicks',$curr_from,$curr_to),      cmp_sum($sd,'clicks',$prev_from,$prev_to)),
            'impressions' => cmp_delta(cmp_sum($sd,'impressions',$curr_from,$curr_to), cmp_sum($sd,'impressions',$prev_from,$prev_to)),
            'position'    => [  // posición: menor es mejor, invertir trend
                'curr'  => round(cmp_avg($sd,'position',$curr_from,$curr_to) ?? 0, 1),
                'prev'  => round(cmp_avg($sd,'position',$prev_from,$prev_to) ?? 0, 1),
                'trend' => (cmp_avg($sd,'position',$curr_from,$curr_to) ?? 99)
                         < (cmp_avg($sd,'position',$prev_from,$prev_to) ?? 99) ? 'up' : 'down',
            ],
        ];
    }

    echo json_encode([
        'ok'         => true,
        'curr_range' => ['from' => $curr_from, 'to' => $curr_to],
        'prev_range' => ['from' => $prev_from, 'to' => $prev_to],
        'days'       => $days,
        'deltas'     => $deltas,
        'has_data'   => !empty($deltas),
    ], JSON_UNESCAPED_UNICODE);
    exit;
}

// ── EXPORT PDF — genera PDF descargable con wkhtmltopdf ──────────────────────
if ($action === 'export_pdf') {
    $report_id = (int)($input['id'] ?? $_GET['id'] ?? 0);
    if (!$report_id) { echo json_encode(['ok'=>false,'error'=>'id requerido']); exit; }

    $row = $pdo->prepare("SELECT r.html, r.period_label, c.name AS client_name
        FROM dm_reports r JOIN dm_clients c ON c.id = r.client_id
        WHERE r.id = ? AND r.client_id = ?");
    $row->execute([$report_id, $client_id]);
    $report = $row->fetch(PDO::FETCH_ASSOC);
    if (!$report) { echo json_encode(['ok'=>false,'error'=>'Reporte no encontrado']); exit; }

    // Buscar wkhtmltopdf
    $wk = '';
    foreach (['/usr/local/bin/wkhtmltopdf','/usr/bin/wkhtmltopdf','/bin/wkhtmltopdf'] as $p) {
        if (file_exists($p) && is_executable($p)) { $wk = $p; break; }
    }
    if (!$wk) {
        $wk = trim((string)@shell_exec('which wkhtmltopdf 2>/dev/null'));
        if (!$wk || !file_exists($wk)) {
            echo json_encode(['ok'=>false,'error'=>'wkhtmltopdf no disponible en servidor']); exit;
        }
    }

    // Guardar HTML en archivo temporal
    $tmp_dir  = sys_get_temp_dir();
    $tmp_html = $tmp_dir . '/dm_rpt_' . $report_id . '_' . time() . '.html';
    $tmp_pdf  = str_replace('.html', '.pdf', $tmp_html);

    file_put_contents($tmp_html, $report['html']);

    $safe_name = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $report['client_name']);
    $safe_per  = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $report['period_label']);
    $filename  = "Reporte_{$safe_name}_{$safe_per}.pdf";

    $cmd = escapeshellarg($wk)
         . ' --quiet --page-size A4 --margin-top 10mm --margin-bottom 10mm'
         . ' --margin-left 10mm --margin-right 10mm'
         . ' --enable-local-file-access'
         . ' ' . escapeshellarg($tmp_html)
         . ' ' . escapeshellarg($tmp_pdf)
         . ' 2>/dev/null';

    $exit_code = -1;
    @exec($cmd, $out, $exit_code);

    // Limpiar HTML temporal
    @unlink($tmp_html);

    if (!file_exists($tmp_pdf) || filesize($tmp_pdf) === 0) {
        echo json_encode(['ok'=>false,'error'=>'Error al generar PDF (código: ' . $exit_code . ')']); exit;
    }

    // Servir como descarga y limpiar
    header('Content-Type: application/pdf');
    header('Content-Disposition: attachment; filename="' . $filename . '"');
    header('Content-Length: ' . filesize($tmp_pdf));
    header('Cache-Control: no-cache');
    readfile($tmp_pdf);
    @unlink($tmp_pdf);
    exit;
}

// ── SEND EMAIL — envía reporte HTML por email al cliente ─────────────────────
if ($action === 'send_email') {
    dm_csrf_verify();
    $report_id   = (int)($input['id'] ?? 0);
    $to_override = trim($input['email'] ?? '');  // email manual, sobrescribe el del cliente

    if (!$report_id) { echo json_encode(['ok'=>false,'error'=>'id requerido']); exit; }

    $row = $pdo->prepare(
        "SELECT r.html, r.period_label, c.name AS client_name, c.contact_email
           FROM dm_reports r
           JOIN dm_clients c ON c.id = r.client_id
          WHERE r.id = ? AND r.client_id = ?"
    );
    $row->execute([$report_id, $client_id]);
    $report = $row->fetch(PDO::FETCH_ASSOC);
    if (!$report) { echo json_encode(['ok'=>false,'error'=>'Reporte no encontrado']); exit; }

    $to = $to_override ?: ($report['contact_email'] ?? '');
    if (!$to || !filter_var($to, FILTER_VALIDATE_EMAIL)) {
        echo json_encode(['ok'=>false,'error'=>'Email de destino no válido. Configura el email del cliente o pasa un email manual.']);
        exit;
    }

    $client_name  = htmlspecialchars($report['client_name']);
    $period_label = htmlspecialchars($report['period_label']);
    $dimark_url   = 'https://dimark.co';
    $logo_url     = 'https://dimark.co/supercerebro/logo.png';  // ajustar si hay logo en servidor
    $from_name    = defined('DIMARK_FROM_NAME') ? DIMARK_FROM_NAME : 'DIMARK';
    $from_email   = 'no-reply@dimark.co';
    $dimark_email = defined('DIMARK_EMAIL') ? DIMARK_EMAIL : 'info@dimark.co';

    // Envolver el HTML del reporte en un email-wrapper limpio
    $email_html = <<<HTML
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<style>
  body{margin:0;padding:0;background:#f4f6fb;font-family:Arial,sans-serif}
  .wrap{max-width:900px;margin:0 auto;background:#fff}
  .header{background:#111827;padding:28px 40px;text-align:center}
  .header img{height:40px;object-fit:contain}
  .header h1{color:#fff;font-size:14px;margin:12px 0 0;letter-spacing:1px;text-transform:uppercase;opacity:.7}
  .badge{display:inline-block;background:#3b82f6;color:#fff;font-size:12px;padding:4px 14px;border-radius:20px;margin:16px 0 0}
  .report-body{padding:0}
  .footer{background:#111827;padding:24px 40px;text-align:center;color:rgba(255,255,255,.5);font-size:12px}
  .footer a{color:#60a5fa;text-decoration:none}
</style>
</head>
<body>
<div class="wrap">
  <div class="header">
    <div style="font-size:22px;font-weight:900;color:#fff;letter-spacing:-1px">DIMARK</div>
    <h1>Reporte de Rendimiento Digital</h1>
    <div class="badge">{$client_name} · {$period_label}</div>
  </div>
  <div class="report-body">
    {$report['html']}
  </div>
  <div class="footer">
    <p>Este reporte fue generado automáticamente por <a href="{$dimark_url}">DIMARK SuperCerebro</a>.</p>
    <p>¿Preguntas? Escríbenos a <a href="mailto:{$dimark_email}">{$dimark_email}</a></p>
    <p style="margin-top:16px;opacity:.4">© {$from_name} · Agencia de Marketing Digital</p>
  </div>
</div>
</body>
</html>
HTML;

    $subject     = "📊 Reporte {$period_label} — {$client_name}";
    $enc_subject = '=?UTF-8?B?' . base64_encode($subject) . '?=';
    $headers     = implode("\r\n", [
        'MIME-Version: 1.0',
        'Content-Type: text/html; charset=UTF-8',
        'From: ' . $from_name . ' <' . $from_email . '>',
        'Reply-To: ' . $dimark_email,
        'X-Mailer: PHP/' . PHP_VERSION,
    ]);

    $sent = @mail($to, $enc_subject, $email_html, $headers);

    // Registrar en dm_activity
    try {
        $pdo->prepare(
            "INSERT INTO dm_activity (user_id, client_id, action, detail, ip) VALUES (?,?,?,?,?)"
        )->execute([
            dm_user()['id'] ?? null,
            $client_id,
            'report_email_sent',
            json_encode(['report_id' => $report_id, 'to' => $to, 'period' => $period_label, 'sent' => $sent]),
            $_SERVER['REMOTE_ADDR'] ?? '',
        ]);
    } catch (Exception $e) {}

    echo json_encode([
        'ok'     => $sent,
        'sent_to'=> $to,
        'error'  => $sent ? null : 'mail() retornó false — verificar configuración SMTP del servidor',
    ], JSON_UNESCAPED_UNICODE);
    exit;
}

// ── GENERATE ─────────────────────────────────────────────────────────────────

$client_row = $pdo->prepare("SELECT * FROM dm_clients WHERE id=?");
$client_row->execute([$client_id]);
$client = $client_row->fetch(PDO::FETCH_ASSOC);
if (!$client) { echo json_encode(['ok'=>false,'error'=>'Cliente no encontrado']); exit; }

$period     = $input['period'] ?? 'last_month';
$date_since = $input['since'] ?? '';
$date_until = $input['until'] ?? '';
$include    = $input['include'] ?? ['meta','google','seo']; // servicios a incluir

if ($date_since && $date_until) {
    $date_from = $date_since; $date_to = $date_until;
    $period_label = date('d M Y', strtotime($date_from)).' — '.date('d M Y', strtotime($date_to));
} else {
    switch ($period) {
        case 'last_7':
            $date_from=date('Y-m-d',strtotime('-7 days')); $date_to=date('Y-m-d');
            $period_label='Últimos 7 días ('.date('d M',strtotime('-7 days')).' — '.date('d M Y').')';
            break;
        case 'last_15':
            $date_from=date('Y-m-d',strtotime('-15 days')); $date_to=date('Y-m-d');
            $period_label='Últimos 15 días ('.date('d M',strtotime('-15 days')).' — '.date('d M Y').')';
            break;
        case 'last_30':
            $date_from=date('Y-m-d',strtotime('-30 days')); $date_to=date('Y-m-d');
            $period_label='Últimos 30 días ('.date('d M',strtotime('-30 days')).' — '.date('d M Y').')';
            break;
        case 'last_90':
            $date_from=date('Y-m-d',strtotime('-90 days')); $date_to=date('Y-m-d');
            $period_label='Últimos 90 días ('.date('d M Y',strtotime('-90 days')).' — '.date('d M Y').')';
            break;
        case 'this_month':
            $date_from=date('Y-m-01'); $date_to=date('Y-m-d');
            $period_label='Mes actual — '.date('F Y');
            break;
        default: // last_month
            $date_from=date('Y-m-01',strtotime('first day of last month'));
            $date_to=date('Y-m-t',strtotime('last month'));
            $period_label='Mes anterior — '.date('F Y',strtotime('last month'));
    }
}

$meta_data=['ok'=>false]; $google_data=['ok'=>false]; $seo_data=['ok'=>false];

// ── RECOPILAR META ADS ────────────────────────────────────────────────────────
if (in_array('meta',$include)) {
    $mc = dm_get_credentials($client_id,'meta');
    $mt = $mc['access_token'] ?? (defined('META_SYSTEM_TOKEN')?META_SYSTEM_TOKEN:'');
    $ma = $mc['ad_account_id'] ?? '';
    if ($mt && $ma) {
        if (strpos($ma,'act_')!==0) $ma='act_'.$ma;
        $tr=json_encode(['since'=>$date_from,'until'=>$date_to]);
        $cr=meta_r("{$ma}/campaigns",[
            'fields'=>'id,name,status,objective,daily_budget,lifetime_budget,insights.time_range('.$tr.'){spend,impressions,clicks,ctr,reach,frequency,cpm,cpc,actions,action_values}',
            'effective_status'=>json_encode(['ACTIVE','PAUSED','WITH_ISSUES']),
            'action_attribution_windows'=>json_encode(['7d_click']),
            'limit'=>50,
        ],$mt);

        $camps=[]; $m_spend=$m_imp=$m_clicks=$m_reach=$m_conv=$m_val=0;
        foreach(($cr['data']??[]) as $c){
            $ci=$c['insights']['data'][0]??[];
            $sp=round((float)($ci['spend']??0),0);
            if($sp<=0) continue; // solo campañas con actividad real en el período
            $conv=0; $val=0;
            foreach(($ci['actions']??[]) as $a){
                $t=$a['action_type']??''; $v=(float)($a['value']??0);
                if(in_array($t,['lead','purchase','complete_registration','messaging_conversation_started_7d','onsite_conversion.messaging_conversation_started_7d','submit_application','contact'])) $conv+=$v;
            }
            foreach(($ci['action_values']??[]) as $a){ if($a['action_type']==='purchase') $val+=(float)($a['value']??0); }
            $m_spend+=$sp; $m_imp+=(int)($ci['impressions']??0); $m_clicks+=(int)($ci['clicks']??0);
            $m_reach+=(int)($ci['reach']??0); $m_conv+=$conv; $m_val+=$val;
            $camps[]=[ 'name'=>$c['name'], 'status'=>strtolower($c['status']),
                'objective'=>str_replace('_',' ',strtolower($c['objective']??'')),
                'spend'=>$sp, 'spend_fmt'=>rfmt($sp),
                'budget'=>parse_budget_r($c['daily_budget']??0,$c['lifetime_budget']??0),
                'impressions'=>(int)($ci['impressions']??0),
                'reach'=>(int)($ci['reach']??0),
                'clicks'=>(int)($ci['clicks']??0),
                'ctr'=>round((float)($ci['ctr']??0),2),
                'cpm'=>round((float)($ci['cpm']??0),0),
                'cpc'=>round((float)($ci['cpc']??0),0),
                'freq'=>round((float)($ci['frequency']??0),2),
                'conv'=>round($conv,0),
                'conv_val'=>round($val,0),
            ];
        }
        usort($camps,fn($a,$b)=>$b['spend']<=>$a['spend']);
        $meta_data=['ok'=>true,'spend'=>$m_spend,'spend_fmt'=>rfmt($m_spend),
            'impressions'=>$m_imp,'clicks'=>$m_clicks,'ctr'=>$m_imp>0?round($m_clicks/$m_imp*100,2):0,
            'reach'=>$m_reach,'conversions'=>round($m_conv,0),'conv_value'=>round($m_val,0),
            'cpa'=>$m_conv>0?round($m_spend/$m_conv,0):0,'cpa_fmt'=>$m_conv>0?rfmt(round($m_spend/$m_conv,0)):'—',
            'roas'=>$m_spend>0&&$m_val>0?round($m_val/$m_spend,2):0,
            'campaigns'=>array_slice($camps,0,8),
        ];
    }
}

function parse_budget_r($daily,$lifetime): string {
    $d=round((float)$daily,0); $l=round((float)$lifetime,0);
    if($d>0) return rfmt($d).'/día';
    if($l>0) return rfmt($l).' total';
    return 'Del Ad Set';
}

// ── RECOPILAR GOOGLE ADS ──────────────────────────────────────────────────────
if (in_array('google',$include)) {
    $gc=dm_get_credentials($client_id,'google');
    $gcid=$gc['customer_id']??(defined('GOOGLE_CUSTOMER_ID')?GOOGLE_CUSTOMER_ID:'');
    $gmcc=$gc['mcc_id']??(defined('GOOGLE_MCC_ID')?GOOGLE_MCC_ID:'');
    $gdev=defined('GOOGLE_DEV_TOKEN')?GOOGLE_DEV_TOKEN:'';
    $gacc=dm_google_access_token();
    if($gacc&&$gcid&&$gdev){
        $gcid_clean=preg_replace('/[^0-9]/','', $gcid);
        if($gacc){
            // Campañas con datos de competencia (impression share)
            $gr=gads_r("SELECT campaign.name,campaign.status,campaign.advertising_channel_type,metrics.cost_micros,metrics.impressions,metrics.clicks,metrics.conversions,metrics.ctr,metrics.average_cpc,metrics.search_impression_share,metrics.search_budget_lost_impression_share,metrics.search_rank_lost_impression_share FROM campaign WHERE segments.date BETWEEN '{$date_from}' AND '{$date_to}' AND metrics.cost_micros > 0 ORDER BY metrics.cost_micros DESC LIMIT 15",$gcid_clean,$gacc,$gdev,$gmcc);
            $g_spend=$g_imp=$g_clicks=$g_conv=0; $g_camps=[];
            foreach(($gr??[]) as $batch){
                foreach(($batch['results']??[]) as $row){
                    $sp=round((float)($row['metrics']['costMicros']??0)/1000000,0);
                    $conv=round((float)($row['metrics']['conversions']??0),1);
                    $g_spend+=$sp; $g_imp+=(int)($row['metrics']['impressions']??0);
                    $g_clicks+=(int)($row['metrics']['clicks']??0); $g_conv+=$conv;
                    $is_val  = $row['metrics']['searchImpressionShare']??null;
                    $is_bdgt = $row['metrics']['searchBudgetLostImpressionShare']??null;
                    $is_rank = $row['metrics']['searchRankLostImpressionShare']??null;
                    $g_camps[]=['name'=>$row['campaign']['name']??'','status'=>strtolower($row['campaign']['status']??''),
                        'type'=>str_replace('_',' ',strtolower($row['campaign']['advertisingChannelType']??'')),
                        'spend'=>$sp,'spend_fmt'=>rfmt($sp),
                        'impressions'=>(int)($row['metrics']['impressions']??0),
                        'clicks'=>(int)($row['metrics']['clicks']??0),
                        'ctr'=>round((float)($row['metrics']['ctr']??0)*100,2),
                        'cpc'=>round((float)($row['metrics']['averageCpc']??0)/1000000,0),
                        'conv'=>$conv,
                        'is'       =>$is_val!==null?round((float)$is_val*100,1):null,
                        'is_budget'=>$is_bdgt!==null?round((float)$is_bdgt*100,1):null,
                        'is_rank'  =>$is_rank!==null?round((float)$is_rank*100,1):null,
                    ];
                }
            }
            // Top keywords
            $kwr=gads_r("SELECT ad_group_criterion.keyword.text,metrics.clicks,metrics.impressions,metrics.average_cpc,metrics.conversions,metrics.search_impression_share FROM keyword_view WHERE segments.date BETWEEN '{$date_from}' AND '{$date_to}' AND metrics.clicks > 0 ORDER BY metrics.clicks DESC LIMIT 10",$gcid_clean,$gacc,$gdev,$gmcc);
            $g_kws=[];
            foreach(($kwr??[]) as $batch){
                foreach(($batch['results']??[]) as $row){
                    $g_kws[]=['kw'=>$row['adGroupCriterion']['keyword']['text']??'',
                        'clicks'=>(int)($row['metrics']['clicks']??0),
                        'imp'=>(int)($row['metrics']['impressions']??0),
                        'cpc'=>round((float)($row['metrics']['averageCpc']??0)/1000000,0),
                        'conv'=>round((float)($row['metrics']['conversions']??0),1),
                    ];
                }
            }
            $google_data=['ok'=>true,'spend'=>$g_spend,'spend_fmt'=>rfmt($g_spend),
                'impressions'=>$g_imp,'clicks'=>$g_clicks,'ctr'=>$g_imp>0?round($g_clicks/$g_imp*100,2):0,
                'conversions'=>$g_conv,'cpa'=>$g_conv>0?round($g_spend/$g_conv,0):0,
                'cpa_fmt'=>$g_conv>0?rfmt(round($g_spend/$g_conv,0)):'—',
                'campaigns'=>$g_camps,'keywords'=>$g_kws,
            ];
        }
    }
}

// ── RECOPILAR SEO ─────────────────────────────────────────────────────────────
if (in_array('seo',$include)) {
    $sc=dm_get_credentials($client_id,'gsc');
    $sref=$sc['refresh_token']??(defined('GOOGLE_REFRESH_TOKEN')?GOOGLE_REFRESH_TOKEN:'');
    $ssite=$sc['domain']??'';
    $gcli2=defined('GOOGLE_CLIENT_ID')?GOOGLE_CLIENT_ID:'';
    $gsec2=defined('GOOGLE_CLIENT_SECRET')?GOOGLE_CLIENT_SECRET:'';
    if($sref&&$ssite){
        $tch=curl_init('https://oauth2.googleapis.com/token');
        curl_setopt_array($tch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2,
            CURLOPT_POSTFIELDS=>http_build_query(['client_id'=>$gcli2,'client_secret'=>$gsec2,'refresh_token'=>$sref,'grant_type'=>'refresh_token'])]);
        $tr3=json_decode(curl_exec($tch),true); curl_close($tch);
        $sacc=$tr3['access_token']??'';
        if($sacc){
            // Métricas globales
            $sch=curl_init("https://searchconsole.googleapis.com/webmasters/v3/sites/".urlencode($ssite)."/searchAnalytics/query");
            curl_setopt_array($sch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2,CURLOPT_TIMEOUT=>20,
                CURLOPT_HTTPHEADER=>['Authorization: Bearer '.$sacc,'Content-Type: application/json'],
                CURLOPT_POSTFIELDS=>json_encode(['startDate'=>$date_from,'endDate'=>$date_to,'dimensions'=>['query'],'rowLimit'=>10])]);
            $sr=json_decode(curl_exec($sch),true); curl_close($sch);
            // Top páginas
            $pch=curl_init("https://searchconsole.googleapis.com/webmasters/v3/sites/".urlencode($ssite)."/searchAnalytics/query");
            curl_setopt_array($pch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2,CURLOPT_TIMEOUT=>20,
                CURLOPT_HTTPHEADER=>['Authorization: Bearer '.$sacc,'Content-Type: application/json'],
                CURLOPT_POSTFIELDS=>json_encode(['startDate'=>$date_from,'endDate'=>$date_to,'dimensions'=>['page'],'rowLimit'=>5])]);
            $pr=json_decode(curl_exec($pch),true); curl_close($pch);
            $s_clicks=$s_imp=$s_pos=0; $s_kws=[];
            foreach(($sr['rows']??[]) as $row){
                $s_clicks+=(int)($row['clicks']??0); $s_imp+=(int)($row['impressions']??0);
                $s_pos+=(float)($row['position']??0);
                $s_kws[]=['kw'=>$row['keys'][0]??'','clicks'=>(int)($row['clicks']??0),'pos'=>round((float)($row['position']??0),1),'ctr'=>round((float)($row['ctr']??0)*100,1)];
            }
            $s_pages=[];
            foreach(($pr['rows']??[]) as $row){
                $url=parse_url($row['keys'][0]??'',PHP_URL_PATH)??$row['keys'][0]??'';
                $s_pages[]=['url'=>$url,'clicks'=>(int)($row['clicks']??0),'imp'=>(int)($row['impressions']??0),'ctr'=>round((float)($row['ctr']??0)*100,1),'pos'=>round((float)($row['position']??0),1)];
            }
            $cnt=count($sr['rows']??[]);
            $seo_data=['ok'=>true,'clicks'=>$s_clicks,'impressions'=>$s_imp,
                'ctr'=>$s_imp>0?round($s_clicks/$s_imp*100,1):0,
                'avg_position'=>$cnt>0?round($s_pos/$cnt,1):0,
                'keywords'=>$s_kws,'pages'=>$s_pages,'site'=>$ssite,
            ];
        }
    }
}

// ── ANÁLISIS CLAUDE ───────────────────────────────────────────────────────────
$api_key=defined('CLAUDE_API_KEY')?CLAUDE_API_KEY:'';
$analysis=[
    'executive'=>'','executions'=>'',
    'meta_strategy'=>'','meta_results'=>'','meta_observations'=>'','meta_competition'=>'',
    'google_strategy'=>'','google_results'=>'','google_observations'=>'','google_competition'=>'',
    'seo_strategy'=>'','seo_results'=>'','seo_observations'=>'','seo_competition'=>'',
    'recommendations'=>[]
];

if($api_key){
    $blks=[];
    if(!empty($meta_data['ok'])){
        $camp_lines=array_map(fn($c)=>"  • \"{$c['name']}\" [{$c['status']}] obj:{$c['objective']} — invertido:{$c['spend_fmt']}, alcance:".rnum($c['reach']).", impr:".rnum($c['impressions']).", CTR:{$c['ctr']}%, frec:{$c['freq']}, CPM:".rfmt($c['cpm']).", CPC:".rfmt($c['cpc']).", conv:{$c['conv']}, presupuesto:{$c['budget']}",$meta_data['campaigns']);
        $blks[]="META ADS — {$period_label}:\nTotales: inversión {$meta_data['spend_fmt']}, alcance ".rnum($meta_data['reach'])." personas, ".rnum($meta_data['impressions'])." impresiones, CTR {$meta_data['ctr']}%, {$meta_data['conversions']} conversiones/leads, CPA {$meta_data['cpa_fmt']}, ROAS {$meta_data['roas']}x, valor conversiones ".rfmt($meta_data['conv_value']??0)."\nDetalle campañas:\n".implode("\n",$camp_lines);
    }
    if(!empty($google_data['ok'])){
        $gcamp_lines=array_map(function($c){
            $is_txt='';
            if($c['is']!==null) $is_txt=", IS:{$c['is']}%";
            if($c['is_budget']!==null) $is_txt.=" (perdido x presupuesto:{$c['is_budget']}%, x posición:{$c['is_rank']}%)";
            return "  • \"{$c['name']}\" [{$c['status']}] tipo:{$c['type']} — {$c['spend_fmt']}, clics:{$c['clicks']}, impr:{$c['impressions']}, CTR:{$c['ctr']}%, CPC:".rfmt($c['cpc']).", conv:{$c['conv']}{$is_txt}";
        },$google_data['campaigns']);
        $gkw_lines=array_map(fn($k)=>"  • \"{$k['kw']}\" — {$k['clicks']} clics, ".rnum($k['imp'])." impr, CTR:".($k['imp']>0?round($k['clicks']/$k['imp']*100,2):'—')."%, CPC:".rfmt($k['cpc']).", {$k['conv']} conv",$google_data['keywords']);
        $blks[]="GOOGLE ADS — {$period_label}:\nTotales: inversión {$google_data['spend_fmt']}, {$google_data['clicks']} clics, ".rnum($google_data['impressions'])." impr, CTR {$google_data['ctr']}%, {$google_data['conversions']} conversiones, CPA {$google_data['cpa_fmt']}\nDetalle campañas (con Impression Share y datos de competencia):\n".implode("\n",$gcamp_lines)."\nTop keywords:\n".implode("\n",$gkw_lines);
    }
    if(!empty($seo_data['ok'])){
        $skw_lines=array_map(fn($k)=>"  • \"{$k['kw']}\" — posición {$k['pos']}, {$k['clicks']} clics, CTR {$k['ctr']}%",$seo_data['keywords']??[]);
        $spg_lines=array_map(fn($p)=>"  • {$p['url']} — {$p['clicks']} clics, pos {$p['pos']}, CTR {$p['ctr']}%",$seo_data['pages']??[]);
        $blks[]="SEO — {$period_label}:\nTotales: ".rnum($seo_data['clicks'])." clics orgánicos, ".rnum($seo_data['impressions'])." impresiones, CTR {$seo_data['ctr']}%, posición promedio {$seo_data['avg_position']}\nTop keywords:\n".implode("\n",$skw_lines)."\nTop páginas:\n".implode("\n",$spg_lines);
    }
    $data_block=implode("\n\n",$blks);
    $modules_inc=implode(', ',array_keys(array_filter(['Meta Ads'=>!empty($meta_data['ok']),'Google Ads'=>!empty($google_data['ok']),'SEO'=>!empty($seo_data['ok'])])));

    $prompt="Eres el Director de Marketing Digital de DIMARK, agencia con 20 años en el mercado latinoamericano. Redacta el informe oficial del cliente \"{$client['name']}\" para {$period_label}. Canales: {$modules_inc}.

DATOS REALES:
{$data_block}

REGLAS: usa números reales del período, menciona nombres de campañas/keywords específicas, tono de experto con el dueño del negocio, sé honesto si algo no funcionó. Omite secciones de canales sin datos (deja el campo en \"\").

Responde SOLO con JSON válido, sin markdown:
{\"executive\":\"5-6 oraciones: inversión total, canal con mejor ROI, resultado principal (leads/ventas/tráfico), tendencia, acción más urgente. Cita números.\",\"executions\":\"4-5 oraciones: qué campañas corrieron exactamente, con qué objetivos, cómo se distribuyó la inversión entre canales y campañas, si hubo cambios o pausas en el período.\",\"meta_strategy\":\"4-5 oraciones: objetivo de las campañas Meta, audiencias targetadas, formatos usados, distribución del presupuesto entre campañas activas.\",\"meta_results\":\"5-6 oraciones: interpreta inversión/alcance/CTR/frecuencia/CPA/ROAS con números exactos. Qué campaña tuvo mejor desempeño y por qué. Evalúa si CTR>1% (saludable) y frecuencia (>3 indica fatiga de audiencia).\",\"meta_observations\":\"4-5 oraciones: qué funcionó, señales de alerta en los datos, qué creativo o audiencia tiene potencial sin explotar, recomendación de A/B test concreta.\",\"meta_competition\":\"3-4 oraciones: analiza frecuencia como indicador de saturación — frecuencia alta (>3) indica que competidores también pauatan en el mismo segmento. Estrategia para diferenciarse.\",\"google_strategy\":\"4-5 oraciones: tipos de campaña activas (Search/Display/PMax), intención de búsqueda capturada, estrategia de puja, distribución del presupuesto, objetivo de conversión.\",\"google_results\":\"5-6 oraciones: interpreta clics/CTR/CPC/conversiones con números. Qué keywords generaron más conversiones. Evalúa si el CPA es rentable. Compara eficiencia entre campañas.\",\"google_observations\":\"4-5 oraciones: keywords con alto gasto y pocas conversiones (candidatos a pausar), keywords con muchas impresiones y bajo CTR (problema de relevancia), oportunidades de nuevas keywords, acción inmediata.\",\"google_competition\":\"4-5 oraciones: interpreta el Impression Share (IS%) — IS>70% indica dominio, IS<30% indica fuerte competencia. Analiza si la pérdida de IS es por presupuesto (aumentar) o por posición/calidad (mejorar relevancia). Conclusión sobre nivel competitivo del nicho.\",\"seo_strategy\":\"3-4 oraciones: en qué categorías tiene visibilidad el cliente, qué tipo de búsquedas captura, enfoque del posicionamiento orgánico.\",\"seo_results\":\"5-6 oraciones: interpreta clics/impresiones/CTR/posición con números. Keywords con mejor rendimiento. Páginas con más tráfico. Evalúa si CTR orgánico es saludable.\",\"seo_observations\":\"4-5 oraciones: keywords en posición 4-10 con potencial de subir al top 3, páginas con muchas impresiones y bajo CTR (necesitan mejor meta-title), 2 acciones concretas para el próximo mes.\",\"seo_competition\":\"3-4 oraciones: posición promedio como indicador competitivo, keywords donde la posición está en zona de riesgo, cómo recuperar terreno frente a competidores.\",\"recommendations\":[{\"priority\":\"alta\",\"area\":\"meta\",\"action\":\"Acción específica con campaña o keyword\",\"reason\":\"Por qué es urgente y qué impacto tendrá\"},{\"priority\":\"alta\",\"area\":\"google\",\"action\":\"Acción específica\",\"reason\":\"Impacto en métricas clave\"},{\"priority\":\"alta\",\"area\":\"seo\",\"action\":\"Acción específica\",\"reason\":\"Por qué no puede esperar\"},{\"priority\":\"media\",\"area\":\"meta\",\"action\":\"Mejora estratégica próximas 2 semanas\",\"reason\":\"Beneficio a mediano plazo\"},{\"priority\":\"media\",\"area\":\"google\",\"action\":\"Mejora estratégica\",\"reason\":\"Mejora posición competitiva\"},{\"priority\":\"baja\",\"area\":\"seo\",\"action\":\"Iniciativa para el próximo mes\",\"reason\":\"Crecimiento a largo plazo\"}]}";

    $ch=curl_init('https://api.anthropic.com/v1/messages');
    curl_setopt_array($ch,[CURLOPT_RETURNTRANSFER=>true,CURLOPT_POST=>true,CURLOPT_SSL_VERIFYPEER => true, CURLOPT_SSL_VERIFYHOST => 2,CURLOPT_TIMEOUT=>90,
        CURLOPT_HTTPHEADER=>['x-api-key:'.$api_key,'anthropic-version:2023-06-01','Content-Type:application/json'],
        CURLOPT_POSTFIELDS=>json_encode(['model'=>'claude-sonnet-4-6','max_tokens'=>8000,
            'messages'=>[['role'=>'user','content'=>$prompt]]])]);
    $raw=curl_exec($ch); $http=curl_getinfo($ch,CURLINFO_HTTP_CODE); curl_close($ch);
    $dbg_http=$http; $dbg_txt=''; $dbg_json_ok=false;
    if($http===200){
        $res=json_decode($raw,true);
        $txt=trim($res['content'][0]['text']??'');
        $dbg_txt=substr($txt,0,300);
        if(preg_match('/\{[\s\S]*\}/s',$txt,$m)){
            $parsed=json_decode($m[0],true);
            if($parsed){ $analysis=array_merge($analysis,$parsed); $dbg_json_ok=true; }
        }
    } else {
        $dbg_txt=substr($raw??'',0,300);
        DmLog::error('reports', 'Claude API error', ['http'=>$http,'response'=>$dbg_txt]);
    }
    if (!$dbg_json_ok) DmLog::warn('reports', 'Claude response JSON parse failed', ['http'=>$dbg_http,'txt'=>$dbg_txt]);
    file_put_contents(__DIR__.'/../logs/reports_debug.log',
        date('[Y-m-d H:i:s]')." HTTP:{$dbg_http} json_ok:".($dbg_json_ok?'yes':'no')." txt:".str_replace("\n"," ",$dbg_txt)."\n",
        FILE_APPEND);
}

// ── ANÁLISIS FALLBACK — se llena con reglas si Claude no respondió ────────────
function fb_fill(array &$analysis, array $md, array $gd, array $sd, string $pl, string $cn): void {
    $hm=!empty($md['ok']); $hg=!empty($gd['ok']); $hs=!empty($sd['ok']);

    // ── helpers internos ──
    $freq_avg = function(array $camps): float {
        $fs=array_filter(array_map(fn($c)=>(float)$c['freq'],$camps),fn($f)=>$f>0);
        return !empty($fs)?round(array_sum($fs)/count($fs),2):0;
    };
    $cpm_avg = function(array $camps): float {
        $vs=array_filter(array_map(fn($c)=>(float)($c['cpm']??0),$camps),fn($v)=>$v>0);
        return !empty($vs)?round(array_sum($vs)/count($vs),0):0;
    };

    // ── RESUMEN EJECUTIVO ──
    if(empty($analysis['executive'])){
        $p=[]; $ti=($md['spend']??0)+($gd['spend']??0);
        if($ti>0) $p[]="Durante {$pl}, {$cn} invirtió un total de ".rfmt($ti)." en canales de publicidad digital gestionados por DIMARK.";
        if($hm&&$hg&&$ti>0){$mp=round(($md['spend']/$ti)*100);$gp=100-$mp;$p[]="La inversión se distribuyó entre Meta Ads con el {$mp}% ({$md['spend_fmt']}) y Google Ads con el {$gp}% ({$gd['spend_fmt']}), estrategia que permite cubrir tanto demanda latente (redes sociales) como demanda activa (búsquedas).";}
        if($hm){
            $ct=$md['conversions']>0?", generando {$md['conversions']} conversiones con CPA de {$md['cpa_fmt']}":"";
            $p[]="Meta Ads alcanzó ".number_format($md['reach'],0,',','.')." personas únicas con ".number_format($md['impressions'],0,',','.')." impresiones y CTR de {$md['ctr']}%{$ct}.";
            if($md['roas']>0) $p[]="El ROAS de Meta fue de {$md['roas']}x, significando que por cada peso invertido se retornaron {$md['roas']} pesos en valor de conversión.";
        }
        if($hg){
            $ct=$gd['conversions']>0?", con {$gd['conversions']} conversiones y CPA de {$gd['cpa_fmt']}":"";
            $p[]="Google Ads capturó {$gd['clicks']} clics de intención activa con CTR de {$gd['ctr']}%{$ct}.";
        }
        if($hs) $p[]="El canal orgánico aportó {$sd['clicks']} clics con posición promedio {$sd['avg_position']}, complementando la estrategia de pago.";
        $analysis['executive']=implode(' ',$p);
    }

    // ── EJECUCIONES ──
    if(empty($analysis['executions'])){
        $p=[];
        if($hm&&!empty($md['campaigns'])){
            $ac=count(array_filter($md['campaigns'],fn($c)=>$c['status']==='active'));
            $pa=count($md['campaigns'])-$ac;
            $names=array_map(fn($c)=>"\"{$c['name']}\" ({$c['spend_fmt']})",array_slice($md['campaigns'],0,4));
            $p[]="En Meta Ads estuvieron activas ".count($md['campaigns'])." campañas con gasto real en el período ({$ac} en estado activo, {$pa} pausadas pero con inversión registrada): ".implode(', ',$names).".";
            if($t=$md['campaigns'][0]??null) $p[]="La campaña de mayor inversión fue \"{$t['name']}\" con {$t['spend_fmt']}, objetivo ".ucfirst($t['objective']??'').", alcanzando ".number_format($t['reach'],0,',','.')." personas y generando {$t['conv']} conversiones.";
            $objs=array_unique(array_filter(array_map(fn($c)=>ucfirst($c['objective']??''),$md['campaigns'])));
            if(count($objs)>1) $p[]="Los objetivos del período en Meta cubrieron: ".implode(', ',$objs).".";
        }
        if($hg&&!empty($gd['campaigns'])){
            $ac=count(array_filter($gd['campaigns'],fn($c)=>$c['status']==='enabled'));
            $names=array_map(fn($c)=>"\"{$c['name']}\" ({$c['spend_fmt']})",array_slice($gd['campaigns'],0,4));
            $p[]="En Google Ads se ejecutaron ".count($gd['campaigns'])." campañas con inversión real ({$ac} activas): ".implode(', ',$names).".";
            if($t=$gd['campaigns'][0]??null) $p[]="La campaña de mayor gasto fue \"{$t['name']}\" ({$t['spend_fmt']}, tipo: ".ucfirst($t['type']??'')."), que generó {$t['clicks']} clics y {$t['conv']} conversiones.";
            if(!empty($gd['keywords'])) $p[]="Las ".count($gd['keywords'])." keywords principales del período acumularon {$gd['clicks']} clics con CPA global de {$gd['cpa_fmt']}.";
        }
        if($hs) $p[]="En SEO, Google Search Console registró actividad en ".count($sd['keywords']??[])." keywords que generaron tráfico orgánico, con el sitio {$sd['site']} posicionado en promedio en la posición {$sd['avg_position']}.";
        $analysis['executions']=implode(' ',$p);
    }

    // ══════════════════════════ META ADS ══════════════════════════
    if($hm){
        // Estrategia Meta
        if(empty($analysis['meta_strategy'])){
            $objs=array_unique(array_filter(array_map(fn($c)=>ucfirst($c['objective']??''),$md['campaigns']??[])));
            $ac=count(array_filter($md['campaigns']??[],fn($c)=>$c['status']==='active'));
            $top3=array_map(fn($c)=>"\"{$c['name']}\" ({$c['spend_fmt']})",array_slice($md['campaigns'],0,3));
            $fa=$freq_avg($md['campaigns']??[]);
            $fa_str=$fa>0?"La frecuencia promedio de {$fa}x indica que cada persona del segmento vio los anuncios aproximadamente {$fa} veces en promedio.":"";
            $analysis['meta_strategy']="Durante {$pl} se operaron ".count($md['campaigns']??[])." campañas en Meta Ads, con objetivos de ".(!empty($objs)?implode(', ',array_slice($objs,0,3)):'conversiones').". La inversión de {$md['spend_fmt']} se concentró principalmente en: ".implode(', ',$top3).". De las campañas activas ({$ac}), la distribución del presupuesto priorizó los objetivos de mayor valor comercial para {$cn}. {$fa_str} Esta estrategia apuntó a generar impacto tanto en awareness (alcance de ".number_format($md['reach'],0,',','.')." personas) como en conversiones directas.";
        }
        // Resultados Meta
        if(empty($analysis['meta_results'])){
            $ce=$md['ctr']>=1.5?"excelente — supera el benchmark de 1.5% para Meta Ads":($md['ctr']>=1.0?"saludable — dentro del rango óptimo de 1–1.5%":"por debajo del benchmark de 1% — señal de que los creativos o audiencias necesitan revisión");
            $fa=$freq_avg($md['campaigns']??[]);
            $fe=$fa>=3.5?"alta ({$fa}x) — indica posible fatiga de audiencia, los usuarios ya han visto los anuncios repetidamente":($fa>=2.0?"normal ({$fa}x) — dentro del rango aceptable (2–3x es ideal)":($fa>0?"baja ({$fa}x) — hay margen para más impacto sin saturar la audiencia":"no disponible"));
            $ct=$md['conversions']>0?"Se generaron {$md['conversions']} conversiones/leads con un CPA promedio de {$md['cpa_fmt']}.":"No se registraron conversiones atribuidas en el período — revisar configuración del píxel y eventos de conversión.";
            $ro=$md['roas']>0?" El ROAS fue de {$md['roas']}x: por cada peso invertido en Meta se retornaron {$md['roas']} pesos en valor de conversión, ".($md['roas']>=3?"indicando una campaña rentable.":"lo que requiere evaluar si el margen del negocio lo justifica."):"";
            $top=$md['campaigns'][0]??null;
            $top_txt=$top?" La campaña de mejor desempeño fue \"{$top['name']}\" con CTR de {$top['ctr']}% y {$top['conv']} conversiones sobre una inversión de {$top['spend_fmt']}.":"";
            $analysis['meta_results']="Inversión total Meta: {$md['spend_fmt']}, alcanzando ".number_format($md['reach'],0,',','.')." personas únicas con ".number_format($md['impressions'],0,',','.')." impresiones totales. El CTR promedio fue {$md['ctr']}% — {$ce}. Frecuencia promedio: {$fe}. {$ct}{$ro}{$top_txt}";
        }
        // Observaciones Meta
        if(empty($analysis['meta_observations'])){
            $obs=[];
            $top=$md['campaigns'][0]??null;
            if($top) $obs[]="La campaña \"{$top['name']}\" concentra {$top['spend_fmt']} de inversión con CTR de {$top['ctr']}%".($top['conv']>0?" y {$top['conv']} conversiones (CPA: ".rfmt($top['cpc']>0?$top['cpc']:0)." aprox.)":""." — es la campaña pivote del período; cualquier ajuste aquí impacta directamente los resultados globales.");
            $lc=array_filter($md['campaigns']??[],fn($c)=>$c['ctr']<1.0&&$c['spend']>0);
            if(!empty($lc)){$ln=array_map(fn($c)=>"\"{$c['name']}\" (CTR {$c['ctr']}%)",$lc);$obs[]="Campañas con CTR crítico (<1%): ".implode(', ',$ln).". Acción inmediata: renovar creativos, probar nuevos textos e imágenes, y revisar si la audiencia está demasiado saturada o no es la correcta.";}
            $hf=array_filter($md['campaigns']??[],fn($c)=>$c['freq']>=3.5);
            if(!empty($hf)){$hn=array_map(fn($c)=>"\"{$c['name']}\" (freq {$c['freq']}x)",$hf);$obs[]="Campañas con fatiga de audiencia detectada (frecuencia ≥3.5x): ".implode(', ',$hn).". Estrategia: rotar el set de creativos, expandir el tamaño de la audiencia o activar exclusiones de usuarios que ya convirtieron.";}
            $hconv=$md['conversions']>0;
            if($hconv&&$md['cpa']>0) $obs[]="El CPA de {$md['cpa_fmt']} debe compararse con el valor del lead o ticket promedio del negocio: si el margen es superior al CPA, la campaña es rentable y debe escalarse.";
            if(!$hconv) $obs[]="Sin conversiones atribuidas — verificar que el píxel de Meta esté disparando correctamente en la página de confirmación y que los eventos estén configurados en el Administrador de Eventos.";
            if($md['ctr']<1.0) $obs[]="El CTR general por debajo del 1% es una señal de alerta. Test A/B prioritario: cambiar imagen/video principal, probar formato Carrusel vs Imagen única, y testear 2 versiones diferentes de copy en las próximas 2 semanas.";
            else $obs[]="El CTR es positivo. La próxima optimización es incrementar el presupuesto de las campañas con mejor CPA un 20-30% semanal, monitoreando que el CPM no suba más del 15% al escalar.";
            $analysis['meta_observations']=implode("\n",$obs);
        }
        // Competencia Meta
        if(empty($analysis['meta_competition'])){
            $fa=$freq_avg($md['campaigns']??[]);
            $cpm=$cpm_avg($md['campaigns']??[]);
            $comp_nivel=$fa>=3.5?"muy alta":($fa>=2.5?"alta":($fa>=1.5?"moderada":"baja o moderada"));
            $cpm_eval=$cpm>=15?"elevado (>{15}/mil), refleja alta competencia por la audiencia objetivo":($cpm>=8?"normal (entre $8-$15/mil), indica competencia moderada en el segmento":"bajo (<$8/mil), el segmento tiene baja competencia o la audiencia es amplia");
            $analysis['meta_competition']="En Meta Ads no existe un indicador directo de share of voice como en Google Ads, pero los datos del período permiten inferir el nivel competitivo del segmento. La frecuencia promedio de {$fa}x indica presión competitiva {$comp_nivel}: cuando múltiples anunciantes apuntan al mismo segmento, el algoritmo de Meta aumenta el CPM (costo por cada mil impresiones) y la frecuencia sube rápidamente porque la audiencia disponible se reduce. El CPM promedio del período fue de ".rfmt($cpm)." — {$cpm_eval}.\n\nUn CTR de {$md['ctr']}% frente a la frecuencia de {$fa}x indica ".($md['ctr']<1.0&&$fa>=2.5?"que la audiencia ya está saturada y la competencia está ganando la atención":"que el mensaje sigue siendo relevante a pesar de la presión competitiva").". La estrategia recomendada para diferenciarse de la competencia es: (1) Desarrollar creativos con propuesta de valor única y clara en los primeros 3 segundos, (2) Crear audiencias lookalike basadas en los compradores existentes del cliente para encontrar segmentos menos competidos, (3) Probar ubicaciones menos saturadas como Reels o Stories donde el CPM suele ser más bajo que en Feed.";
        }
    }

    // ══════════════════════════ GOOGLE ADS ══════════════════════════
    if($hg){
        // Estrategia Google
        if(empty($analysis['google_strategy'])){
            $types=array_unique(array_filter(array_map(fn($c)=>ucfirst($c['type']??''),$gd['campaigns']??[])));
            $ac=count(array_filter($gd['campaigns']??[],fn($c)=>$c['status']==='enabled'));
            $top3=array_map(fn($c)=>"\"{$c['name']}\" ({$c['spend_fmt']})",array_slice($gd['campaigns'],0,3));
            $kw_top=!empty($gd['keywords'])?array_map(fn($k)=>"\"{$k['kw']}\"",array_slice($gd['keywords'],0,4)):[];
            $cpa_str=$gd['conversions']>0?"con un CPA real de {$gd['cpa_fmt']} en el período":"sin conversiones atribuidas en el período";
            $analysis['google_strategy']="Google Ads operó ".count($gd['campaigns']??[])." campañas de tipo ".(!empty($types)?implode(' y ',array_slice($types,0,3)):'Search')." ({$ac} activas), con una inversión total de {$gd['spend_fmt']} orientada a capturar usuarios con intención de búsqueda activa. Las campañas principales fueron: ".implode(', ',$top3).". La estrategia se enfocó en keywords de intención comercial para capturar demanda en el momento exacto de búsqueda, {$cpa_str}. ".(!empty($kw_top)?"Las keywords con más tráfico en el período incluyeron: ".implode(', ',$kw_top).".":"")." Este canal complementa Meta Ads cubriendo la parte baja del embudo de conversión, donde el usuario ya tiene intención declarada.";
        }
        // Resultados Google
        if(empty($analysis['google_results'])){
            $ce=$gd['ctr']>=5.0?"excelente — supera el benchmark de 5% para Search":($gd['ctr']>=3.0?"saludable — dentro del rango normal de 3–5% para Search":"bajo — por debajo del 3% benchmark para Search, indica problemas de relevancia entre keyword, anuncio y landing page");
            $ct=$gd['conversions']>0?"Se generaron {$gd['conversions']} conversiones con CPA promedio de {$gd['cpa_fmt']}.":"No se registraron conversiones atribuidas — verificar configuración de conversiones en Google Ads y Google Analytics.";
            $top=$gd['campaigns'][0]??null;
            $top_txt=$top?" La campaña más eficiente fue \"{$top['name']}\" con {$top['spend_fmt']} invertidos, {$top['clicks']} clics, CTR {$top['ctr']}% y {$top['conv']} conversiones.":"";
            $kw_top=$gd['keywords'][0]??null;
            $kw_txt=$kw_top?" La keyword de mayor rendimiento fue \"{$kw_top['kw']}\" con {$kw_top['clicks']} clics y {$kw_top['conv']} conversiones.":"";
            $analysis['google_results']="Google Ads generó {$gd['clicks']} clics sobre ".number_format($gd['impressions'],0,',','.')." impresiones, con CTR promedio de {$gd['ctr']}% — {$ce}. {$ct}{$top_txt}{$kw_txt} La inversión total de {$gd['spend_fmt']} se distribuyó en ".count($gd['campaigns']??[])." campañas activas con foco en captura de intención de búsqueda.";
        }
        // Observaciones Google
        if(empty($analysis['google_observations'])){
            $obs=[];
            $top_kw=$gd['keywords'][0]??null;
            if($top_kw) $obs[]="La keyword estrella del período fue \"{$top_kw['kw']}\" con {$top_kw['clicks']} clics y {$top_kw['conv']} conversiones — asegurarse de que tenga puja suficiente y no esté limitada por presupuesto.";
            $zc=array_filter($gd['keywords']??[],fn($k)=>$k['conv']==0&&$k['clicks']>=5);
            if(!empty($zc)){$zn=array_map(fn($k)=>"\"{$k['kw']}\" ({$k['clicks']} clics, CPC ".rfmt($k['cpc']).")",$zc);$obs[]="Keywords con gasto sin retorno: ".implode(', ',$zn).". Acción: bajar puja un 30% o pausar temporalmente para revisar si la landing page es relevante para esas búsquedas.";}
            $zcc=array_filter($gd['campaigns']??[],fn($c)=>$c['conv']==0&&$c['spend']>50);
            if(!empty($zcc)){$zcn=array_map(fn($c)=>"\"{$c['name']}\" ({$c['spend_fmt']})",$zcc);$obs[]="Campañas con inversión sin conversiones: ".implode(', ',$zcn).". Revisar la landing page de destino, la relevancia del anuncio y si el seguimiento de conversiones está activo.";}
            if($gd['ctr']<3.0) $obs[]="CTR general del {$gd['ctr']}% está por debajo del 3% benchmark para Search. Acciones concretas: (1) Revisar y mejorar los titulares de los RSAs con keywords exactas del término de búsqueda, (2) Agregar más extensiones de anuncio (sitelinks, llamadas, ubicación), (3) Verificar que el Nivel de Calidad (Quality Score) de las keywords principales sea ≥7.";
            else $obs[]="CTR del {$gd['ctr']}% es saludable. Oportunidad de optimización: revisar el informe de Términos de Búsqueda semanalmente para identificar nuevas keywords de cola larga con intención alta que aún no están en el grupo de anuncios.";
            $obs[]="Acción prioritaria: descargar el informe de Términos de Búsqueda del período y agregar como negativas todos los términos irrelevantes — esto puede mejorar el CPA entre un 10-20%.";
            $analysis['google_observations']=implode("\n",$obs);
        }
        // Competencia Google (IS%)
        if(empty($analysis['google_competition'])){
            $ci=array_filter($gd['campaigns']??[],fn($c)=>$c['is']!==null);
            if(!empty($ci)){
                $ai=round(array_sum(array_map(fn($c)=>(float)$c['is'],$ci))/count($ci),1);
                $bl=round(array_sum(array_map(fn($c)=>(float)($c['is_budget']??0),$ci))/count($ci),1);
                $rl=round(array_sum(array_map(fn($c)=>(float)($c['is_rank']??0),$ci))/count($ci),1);
                $lost=round(100-$ai,1);
                $ie=$ai>=70?"dominio fuerte del mercado — la marca está ganando la mayoría de las subastas":($ai>=50?"presencia sólida — se gana más de la mitad de las subastas disponibles":($ai>=30?"presencia moderada — la competencia gana más de la mitad de las oportunidades":"presencia débil — los competidores dominan el espacio pagado en este nicho"));
                $causa_principal=''; $accion_principal='';
                if($bl>$rl&&$bl>5){
                    $causa_principal="La causa principal de pérdida de impresiones es el PRESUPUESTO ({$bl}% perdido x presupuesto vs {$rl}% x posición)";
                    $accion_principal="Aumentar el presupuesto diario de las campañas afectadas recuperaría directamente el IS perdido — cada peso adicional en presupuesto se traduce en más subastas ganadas sin necesidad de mejorar la calidad.";
                } elseif($rl>$bl&&$rl>10){
                    $causa_principal="La causa principal de pérdida es la POSICIÓN/CALIDAD ({$rl}% perdido x posición vs {$bl}% x presupuesto)";
                    $accion_principal="El presupuesto es suficiente, pero los anuncios están perdiendo subastas por Ad Rank bajo. Estrategia: mejorar el Quality Score (relevancia keyword-anuncio-landing), revisar extensiones de anuncio y considerar aumentar las pujas en keywords clave.";
                } else {
                    $causa_principal="La pérdida de IS se distribuye entre presupuesto ({$bl}%) y posición ({$rl}%)";
                    $accion_principal="Abordar ambos frentes: incremento moderado de presupuesto (15-20%) y revisión del Quality Score para mejorar el Ad Rank.";
                }
                // detalle por campaña
                $camp_is_lines=[];
                foreach(array_slice($ci,0,4) as $c){
                    $is_txt=$c['is']!==null?$c['is'].'%':'—';
                    $bl_txt=$c['is_budget']!==null?$c['is_budget'].'%':'—';
                    $rl_txt=$c['is_rank']!==null?$c['is_rank'].'%':'—';
                    $camp_is_lines[]="\"{$c['name']}\": IS {$is_txt} (perdido x presupuesto: {$bl_txt}, x posición: {$rl_txt})";
                }
                $analysis['google_competition']="El Impression Share (IS%) mide qué porcentaje de subastas disponibles en Google ganó cada campaña durante el período. El IS promedio fue de {$ai}%, lo que indica {$ie}. Se está perdiendo el {$lost}% de las oportunidades disponibles frente a los competidores.\n\n{$causa_principal}. {$accion_principal}\n\nDetalle por campaña: ".implode('; ',$camp_is_lines).".\n\nContexto competitivo: IS >70% es el objetivo para campañas de marca donde no debe haber competencia. Para campañas genéricas (servicios o productos), un IS de 40-60% es competitivo. Un IS <30% en campañas core indica que competidores con mayor presupuesto o mejor Quality Score están dominando las búsquedas más valiosas del negocio.";
            } else {
                $analysis['google_competition']="Los datos de Impression Share no están disponibles para este período. El IS% es el indicador más directo de posición competitiva en Google Ads: mide qué porcentaje de las subastas disponibles se está ganando frente a la competencia. Un IS alto (>70%) indica dominio del espacio pagado; un IS bajo (<30%) significa que los competidores están ganando la mayoría de las búsquedas relevantes del negocio.\n\nPara activar este dato: en la interfaz de Google Ads, agregar las columnas 'Impr. (pct. rec.)' (Impression Share), 'Impr. perdidas (cuota de impr.) por presupuesto' e 'Impr. perdidas (cuota de impr.) por posición' en la vista de campañas. Esto permitirá diagnosticar si las pérdidas son por presupuesto insuficiente o por baja calidad de los anuncios.";
            }
        }
    }

    // ══════════════════════════ SEO ══════════════════════════
    if($hs){
        // Estrategia SEO
        if(empty($analysis['seo_strategy'])){
            $tk1=!empty($sd['keywords'])?$sd['keywords'][0]['kw']:'';
            $tk2=!empty($sd['keywords'][1])?$sd['keywords'][1]['kw']:'';
            $top_kws=array_map(fn($k)=>"\"{$k['kw']}\" (pos. {$k['pos']}, {$k['clicks']} clics)",array_slice($sd['keywords']??[],0,4));
            $top_pages=!empty($sd['pages'])?array_map(fn($p)=>"{$p['url']} ({$p['clicks']} clics)",array_slice($sd['pages'],0,3)):[];
            $analysis['seo_strategy']="El sitio {$sd['site']} registra ".number_format($sd['clicks'],0,',','.')." clics orgánicos en Google durante {$pl}, con ".number_format($sd['impressions'],0,',','.')." impresiones totales. La visibilidad orgánica se concentra en keywords de búsqueda activa".($tk1?" como \"{$tk1}\"".($tk2?" y \"{$tk2}\"":""):"").". Las keywords con mejor desempeño fueron: ".implode(', ',$top_kws).".".(!empty($top_pages)?(" Las páginas con más tráfico orgánico: ".implode(', ',$top_pages)."."):"")." La posición promedio de {$sd['avg_position']} indica ".($sd['avg_position']<=3?"dominio en las búsquedas objetivo":($sd['avg_position']<=10?"presencia en primera página que puede mejorar al top 3":"que hay trabajo pendiente para alcanzar la primera página en las keywords principales")).".";
        }
        // Resultados SEO
        if(empty($analysis['seo_results'])){
            $ce=$sd['ctr']>=5.0?"excelente — muy por encima del benchmark orgánico de 3-5%":($sd['ctr']>=2.0?"normal — dentro del rango esperable para resultados orgánicos":"bajo — los snippets en Google (meta-títulos y meta-descripciones) necesitan optimización urgente para mejorar el CTR");
            $pe=$sd['avg_position']<=3.0?"top 3, máxima visibilidad orgánica":($sd['avg_position']<=10.0?"primera página, buena visibilidad — con optimización se puede subir al top 3":"fuera de la primera página — requiere estrategia activa de contenido y link building");
            $kw_perf=array_filter($sd['keywords']??[],fn($k)=>$k['clicks']>0);
            $analysis['seo_results']="Durante {$pl}, el sitio generó ".number_format($sd['clicks'],0,',','.')." clics orgánicos sobre ".number_format($sd['impressions'],0,',','.')." impresiones en Google. CTR orgánico: {$sd['ctr']}% — {$ce}. Posición promedio: {$sd['avg_position']} — {$pe}. Se detectaron ".count($kw_perf)." keywords activas con clics en el período. El CTR orgánico de {$sd['ctr']}% frente al número de impresiones indica ".($sd['ctr']<2.0&&$sd['impressions']>500?"que hay una oportunidad grande de aumentar el tráfico sin necesidad de subir posiciones, solo mejorando los meta-títulos en las páginas actuales.":"que los snippets son relevantes para las búsquedas y los usuarios eligen el resultado del sitio.").($sd['avg_position']>10?" Con posición promedio de {$sd['avg_position']}, el potencial de tráfico orgánico disponible aún no se está aprovechando — las páginas aparecen en resultados pero en posiciones donde pocos usuarios llegan.":"");
        }
        // Observaciones SEO
        if(empty($analysis['seo_observations'])){
            $obs=[];
            $mk=array_filter($sd['keywords']??[],fn($k)=>$k['pos']>=4&&$k['pos']<=10);
            if(!empty($mk)){
                $mn=array_map(fn($k)=>"\"{$k['kw']}\" (pos. {$k['pos']}, {$k['clicks']} clics, CTR {$k['ctr']}%)",array_slice(array_values($mk),0,3));
                $obs[]="Keywords en zona de oportunidad (posición 4-10): ".implode(', ',$mn).". Estas keywords ya están en primera página pero fuera del top 3 — con optimización de contenido (actualizar la página, agregar más texto relevante, mejorar el título H1 y meta-title) pueden subir al top 3 en 4-8 semanas, lo que típicamente triplica los clics.";
            }
            $lk=array_filter($sd['keywords']??[],fn($k)=>$k['ctr']<2.0&&$k['pos']<=5);
            if(!empty($lk)){
                $ln=array_map(fn($k)=>"\"{$k['kw']}\" (CTR {$k['ctr']}%, pos. {$k['pos']})",$lk);
                $obs[]="Keywords en top 5 con CTR bajo: ".implode(', ',$ln).". Estar en top 5 con CTR <2% indica que el snippet (meta-título + descripción) no es atractivo o no coincide con lo que el usuario espera encontrar. Acción: reescribir meta-título incluyendo la keyword exacta y un beneficio claro, y mejorar la meta-descripción con llamada a la acción.";
            }
            if(!empty($sd['pages'])){
                $top_page=$sd['pages'][0];
                $obs[]="La página con más tráfico orgánico es \"{$top_page['url']}\" ({$top_page['clicks']} clics, pos. {$top_page['pos']}, CTR {$top_page['ctr']}%) — esta es la página de entrada principal del canal orgánico; asegurarse de que tenga un CTA claro para convertir ese tráfico.";
            }
            if($sd['avg_position']>10) $obs[]="Posición promedio de {$sd['avg_position']} indica que el sitio no aparece consistentemente en la primera página. Prioridad: identificar las 5 keywords más valiosas del negocio y crear o mejorar una página dedicada para cada una, con contenido de al menos 800 palabras, estructura de headings correcta y datos estructurados.";
            else $obs[]="Posición promedio de {$sd['avg_position']} es positiva. Próximos pasos: (1) Crear contenido de blog orientado a keywords long-tail de menor competencia para aumentar las impresiones, (2) Conseguir backlinks de calidad de directorios del sector y medios locales para fortalecer la autoridad del dominio.";
            $analysis['seo_observations']=implode("\n",$obs);
        }
        // Competencia SEO
        if(empty($analysis['seo_competition'])){
            $pos_nivel=$sd['avg_position']<=3?"dominante — el sitio aparece en las primeras posiciones donde la mayoría de los clics ocurren":($sd['avg_position']<=10?"competitiva — está en primera página pero hay competidores mejor posicionados en el top 3":($sd['avg_position']<=20?"media — el sitio aparece en resultados pero en posiciones donde el usuario raramente llega":"débil — la mayoría de las búsquedas relevantes las están ganando los competidores"));
            $ctr_comp=$sd['ctr']>=3.0?"superior al promedio, lo que indica que el título y descripción son más atractivos que los de los competidores para ese segmento":($sd['ctr']>=1.5?"normal, similar al de competidores en posiciones equivalentes":"inferior al promedio — competidores con snippets mejor optimizados están robando clics aunque el sitio aparezca en posición similar");
            $mk=array_filter($sd['keywords']??[],fn($k)=>$k['pos']>=4&&$k['pos']<=10);
            $risk_kws=array_filter($sd['keywords']??[],fn($k)=>$k['pos']>=8&&$k['pos']<=12);
            $analysis['seo_competition']="La posición promedio de {$sd['avg_position']} indica una presencia orgánica {$pos_nivel}. El CTR orgánico de {$sd['ctr']}% es {$ctr_comp}.\n\nAnálisis competitivo por zona de posición:\n• Top 3 (capturas la mayoría de los clics): ".count(array_filter($sd['keywords']??[],fn($k)=>$k['pos']<=3))." keywords del sitio están en esta zona.\n• Posición 4-10 (primera página, zona de recuperación): ".count($mk)." keywords con potencial real de subir al top 3 con optimización.\n• Posición 11-20 (segunda página, zona de riesgo): ".count($risk_kws)." keywords donde un competidor puede consolidarse si el sitio no mejora.\n\nLa principal amenaza competitiva en SEO son los sitios con mayor autoridad de dominio y más contenido publicado que compiten por las mismas keywords. Para recuperar terreno: (1) Actualizar el contenido existente con información más reciente y completa que la competencia, (2) Obtener backlinks de directorios relevantes del sector y medios de comunicación local, (3) Mejorar la velocidad de carga del sitio (Core Web Vitals) que Google usa como factor de ranking desde 2021.";
        }
    }

    // ══════════════════════════ RECOMENDACIONES ══════════════════════════
    if(empty($analysis['recommendations'])){
        $recs=[];

        // Meta recomendaciones
        if($hm){
            $hf=array_filter($md['campaigns']??[],fn($c)=>$c['freq']>=3.5);
            if(!empty($hf)){
                $hn=implode(', ',array_map(fn($c)=>"\"{$c['name']}\" (freq {$c['freq']}x)",$hf));
                $recs[]=['priority'=>'alta','area'=>'meta','action'=>"Renovar set de creativos en campañas con fatiga de audiencia: {$hn}",'reason'=>"Frecuencia ≥3.5x indica que el usuario ya vio el anuncio demasiadas veces — el CTR caerá y el CPA subirá en las próximas semanas si no se rotan los creativos. Preparar al menos 3 variantes nuevas de imagen/video y 2 versiones de copy para testear."];
            }
            $t=$md['campaigns'][0]??null;
            if($t&&$t['conv']>0){
                $recs[]=['priority'=>'alta','area'=>'meta','action'=>"Escalar la campaña \"{$t['name']}\" aumentando el presupuesto un 20-30% semanal",'reason'=>"Es la campaña con mejor desempeño del período ({$t['spend_fmt']} invertidos, {$t['conv']} conversiones). El escalado gradual del 20-30% semanal permite que el algoritmo de Meta se adapte sin perder eficiencia. Monitorear que el CPM no suba más del 15%."];
            } elseif($t&&$t['conv']==0) {
                $recs[]=['priority'=>'alta','area'=>'meta','action'=>"Auditar el píxel de Meta y los eventos de conversión en \"{$t['name']}\"",'reason'=>"La campaña con mayor inversión ({$t['spend_fmt']}) no registra conversiones. Antes de invertir más, confirmar que el píxel está disparando en la página de confirmación usando Meta Pixel Helper y que los eventos de compra/lead están activos en el Administrador de Eventos."];
            }
            $lc=array_filter($md['campaigns']??[],fn($c)=>$c['ctr']<1.0&&$c['spend']>50);
            if(!empty($lc)){
                $ln=implode(', ',array_map(fn($c)=>"\"{$c['name']}\" (CTR {$c['ctr']}%, invertido {$c['spend_fmt']})",$lc));
                $recs[]=['priority'=>'media','area'=>'meta','action'=>"Test A/B de creativos en campañas con CTR crítico: {$ln}",'reason'=>"CTR <1% en estas campañas indica que el anuncio no está generando suficiente atención. Acción: crear 3 variantes de imagen/video con distintos hooks visuales y textos de apertura; pausar la versión perdedora después de 7 días o 1,000 impresiones por variante."];
            }
        }

        // Google recomendaciones
        if($hg){
            $zc=array_filter($gd['campaigns']??[],fn($c)=>$c['conv']==0&&$c['spend']>100);
            if(!empty($zc)){
                $zn=implode(', ',array_map(fn($c)=>"\"{$c['name']}\" ({$c['spend_fmt']})",$zc));
                $recs[]=['priority'=>'alta','area'=>'google','action'=>"Auditar campañas con gasto sin conversiones: {$zn}",'reason'=>"Estas campañas acumularon inversión sin retorno medible. Pasos: (1) verificar que el seguimiento de conversiones está activo en Google Ads, (2) revisar la landing page de destino — velocidad de carga, CTA visible y formulario funcional, (3) si el tracking está correcto y el CTR es >3%, el problema está en la landing."];
            }
            $li=array_filter($gd['campaigns']??[],fn($c)=>$c['is']!==null&&$c['is']<30);
            if(!empty($li)){
                $ln=implode(', ',array_map(fn($c)=>"\"{$c['name']}\" (IS {$c['is']}%)",$li));
                $bl_avg=round(array_sum(array_map(fn($c)=>(float)($c['is_budget']??0),$li))/count($li),1);
                $rl_avg=round(array_sum(array_map(fn($c)=>(float)($c['is_rank']??0),$li))/count($li),1);
                $causa=$bl_avg>$rl_avg?"aumentar el presupuesto diario (causa principal: presupuesto {$bl_avg}%)":"mejorar Quality Score de las keywords (causa principal: posición {$rl_avg}%)";
                $recs[]=['priority'=>'alta','area'=>'google','action'=>"Recuperar Impression Share en campañas con IS <30%: {$ln}",'reason'=>"IS <30% significa perder el 70%+ de las subastas disponibles frente a competidores. La acción prioritaria es {$causa}. Cada punto de IS recuperado equivale a más impresiones y clics sin cambiar el CPC."];
            }
            $zk=array_filter($gd['keywords']??[],fn($k)=>$k['conv']==0&&$k['clicks']>=5);
            if(!empty($zk)){
                $zn=implode(', ',array_map(fn($k)=>"\"{$k['kw']}\" ({$k['clicks']} clics, CPC ".rfmt($k['cpc']).")",$zk));
                $recs[]=['priority'=>'media','area'=>'google','action'=>"Revisar keywords con clics sin conversiones: {$zn}",'reason'=>"Estas keywords generan tráfico pero no convierten. Opciones: (1) bajar la puja un 30%, (2) revisar si la página de destino es coherente con la intención de búsqueda, (3) verificar si son búsquedas informacionales que nunca convertirán y agregarlas como negativas."];
            }
            if(empty($li)&&empty($zc)){
                $recs[]=['priority'=>'media','area'=>'google','action'=>"Expandir la lista de palabras clave negativas usando el informe de Términos de Búsqueda",'reason'=>"Incluso con buen desempeño, el informe de términos siempre revela búsquedas irrelevantes que consumen presupuesto. Revisión semanal de este informe puede reducir el CPA un 10-20% sin cambiar la estructura de campañas."];
            }
        }

        // SEO recomendaciones
        if($hs){
            $mk=array_filter($sd['keywords']??[],fn($k)=>$k['pos']>=4&&$k['pos']<=10);
            if(!empty($mk)){
                $mk0=array_values($mk)[0];
                $recs[]=['priority'=>'media','area'=>'seo','action'=>"Optimizar la página que posiciona para \"{$mk0['kw']}\" (posición {$mk0['pos']}, {$mk0['clicks']} clics)",'reason'=>"Está en primera página pero fuera del top 3 — subir de posición {$mk0['pos']} a top 3 puede triplicar los clics sin inversión adicional. Acción: agregar la keyword al H1 y meta-title, expandir el contenido con al menos 300 palabras adicionales relevantes, y agregar datos estructurados (Schema.org) si aplica."];
            }
            $lk=array_filter($sd['keywords']??[],fn($k)=>$k['ctr']<2.0&&$k['pos']<=5&&$k['pos']>0);
            if(!empty($lk)){
                $lk0=array_values($lk)[0];
                $recs[]=['priority'=>'media','area'=>'seo','action'=>"Reescribir meta-título y meta-descripción de la página que posiciona para \"{$lk0['kw']}\" (CTR {$lk0['ctr']}%)",'reason'=>"Está en posición {$lk0['pos']} (muy visible) pero solo el {$lk0['ctr']}% hace clic. El título actual no está atrayendo suficiente atención. Incluir la keyword exacta, un beneficio claro y un número o dato específico en el meta-title puede llevar el CTR a 4-6%."];
            }
            if(empty($mk)&&empty($lk)){
                $recs[]=['priority'=>'baja','area'=>'seo','action'=>"Crear contenido de blog con 4-6 artículos orientados a keywords de long-tail del negocio",'reason'=>"Ampliar la presencia orgánica en keywords de baja competencia genera tráfico cualificado a largo plazo y reduce la dependencia de publicidad pagada. Objetivo: publicar 1 artículo por semana durante el próximo mes."];
            }
        }

        while(count($recs)<4){
            $recs[]=['priority'=>'baja','area'=>'general','action'=>'Configurar reportes automáticos semanales en Google Ads y Meta Ads para monitoreo continuo','reason'=>'El monitoreo frecuente permite detectar caídas de rendimiento antes de que impacten el presupuesto del mes.'];
        }
        $analysis['recommendations']=array_slice($recs,0,8);
    }
}
fb_fill($analysis,$meta_data,$google_data,$seo_data,$period_label,$client['name']);

// ── CONSTRUIR HTML ────────────────────────────────────────────────────────────
$logo_tag = '';
if (!empty($client['report_use_logo'])) {
    // 1. Buscar en dm_brand_assets (fuente principal)
    try {
        $la = $pdo->prepare("SELECT file_path FROM dm_brand_assets WHERE client_id=? AND type='logo' ORDER BY id DESC LIMIT 1");
        $la->execute([$client_id]);
        $la_row = $la->fetch(PDO::FETCH_ASSOC);
        if ($la_row && !empty($la_row['file_path'])) {
            $logo_abs = __DIR__ . '/../' . ltrim($la_row['file_path'], '/');
            if (file_exists($logo_abs)) {
                $ext  = pathinfo($logo_abs, PATHINFO_EXTENSION);
                $ld   = base64_encode(file_get_contents($logo_abs));
                $mime = $ext === 'svg' ? 'image/svg+xml' : 'image/' . $ext;
                $logo_tag = '<img src="data:' . $mime . ';base64,' . $ld . '" alt="Logo" style="max-height:48px;max-width:150px;object-fit:contain">';
            }
        }
    } catch (\Throwable $e) {}

    // 2. Fallback: uploads/brand/{client_id}/logo.*
    if (!$logo_tag) {
        $logo_files = glob(__DIR__ . '/../uploads/brand/' . $client_id . '/logo.*');
        if ($logo_files) {
            $ext  = pathinfo($logo_files[0], PATHINFO_EXTENSION);
            $ld   = base64_encode(file_get_contents($logo_files[0]));
            $mime = $ext === 'svg' ? 'image/svg+xml' : 'image/' . $ext;
            $logo_tag = '<img src="data:' . $mime . ';base64,' . $ld . '" alt="Logo" style="max-height:48px;max-width:150px;object-fit:contain">';
        }
    }
}
$gen_date=date('d \d\e F \d\e Y');
$h=fn(string $s):string=>htmlspecialchars($s,ENT_QUOTES,'UTF-8');
$total_inv=($meta_data['spend']??0)+($google_data['spend']??0);

// Helpers de tabla
function tr_camp(array $c, string $type='meta'): string {
    $badge=$c['status']==='active'||$c['status']==='enabled'
        ?'<span style="background:#dcfce7;color:#15803d;padding:2px 8px;border-radius:12px;font-size:10px;font-weight:600">Activa</span>'
        :'<span style="background:#fef9c3;color:#a16207;padding:2px 8px;border-radius:12px;font-size:10px;font-weight:600">Pausada</span>';
    $extra=$type==='meta'
        ?'<td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;text-align:right">'.($c['freq']>0?$c['freq']:'—').'</td><td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;text-align:right">'.($c['conv']>0?rnum($c['conv']):'—').'</td>'
        :'<td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;text-align:right">'.rfmt($c['cpc']??0).'</td><td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;text-align:right">'.($c['conv']>0?rnum($c['conv']):'—').'</td>';
    $obj=$type==='meta'?'<td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;font-size:10px;color:#64748b">'.ucfirst($c['objective']??'').'</td>':'<td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;font-size:10px;color:#64748b">'.ucfirst($c['type']??'').'</td>';
    return '<tr><td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;font-size:11px;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap">'.htmlspecialchars($c['name'],ENT_QUOTES,'UTF-8').'</td>'.$badge_td=$badge?'<td style="padding:7px 10px;border-bottom:1px solid #f1f5f9">'.$badge.'</td>':''
        .$obj
        .'<td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;text-align:right;font-weight:700">'.$c['spend_fmt'].'</td>'
        .'<td style="padding:7px 10px;border-bottom:1px solid #f1f5f9;text-align:right">'.($c['ctr']>0?$c['ctr'].'%':'—').'</td>'
        .$extra.'</tr>';
}

ob_start(); ?>
<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<title>Reporte — <?= $h($client['name']) ?> — <?= $h($period_label) ?></title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Helvetica Neue',Arial,sans-serif;font-size:13px;color:#1e293b;background:#f1f5f9}
.page{max-width:920px;margin:0 auto;background:#fff;box-shadow:0 2px 12px rgba(0,0,0,.08)}
.rh{background:linear-gradient(130deg,#0f172a 0%,#e8272a 100%);color:#fff;padding:36px 48px;display:flex;justify-content:space-between;align-items:flex-start}
.rh h1{font-size:20px;font-weight:700;margin-top:8px}
.rh p{font-size:12px;opacity:.7;margin-top:3px}
.rh-r{text-align:right}.rh-r .per{font-size:16px;font-weight:700}
.rh-r .gen{font-size:10px;opacity:.6;margin-top:4px}
.totals{display:flex;gap:16px;padding:24px 48px 0}
.tc{flex:1;background:#f8fafc;border:1px solid #e2e8f0;border-radius:10px;padding:16px 18px;text-align:center}
.tc .v{font-size:22px;font-weight:800;color:#0f172a}.tc .l{font-size:10px;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin-top:3px}
.tc.hi{border-color:#e8272a;background:#fff5f5}.tc.hi .v{color:#e8272a}
.exec{margin:24px 48px;background:#f0f9ff;border-left:4px solid #e8272a;border-radius:0 8px 8px 0;padding:18px 22px}
.exec .lbl{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:#e8272a;margin-bottom:7px}
.exec p{font-size:13px;line-height:1.75;color:#334155}
.sec{margin:0 48px 32px}
.sh{display:flex;align-items:center;gap:10px;margin-bottom:14px;padding-bottom:10px;border-bottom:2px solid #f1f5f9}
.si{width:34px;height:34px;border-radius:8px;display:flex;align-items:center;justify-content:center;font-size:17px}
.si.m{background:#eff6ff}.si.g{background:#f0fdf4}.si.s{background:#fefce8}
.sh h2{font-size:14px;font-weight:700}.sh .src{font-size:11px;color:#94a3b8;margin-left:auto}
.mg{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-bottom:14px}
.mc{background:#f8fafc;border:1px solid #e2e8f0;border-radius:8px;padding:12px 14px}
.mc .mv{font-size:17px;font-weight:700}.mc .ml{font-size:10px;color:#64748b;margin-top:2px}
.mc.hi{border-color:#e8272a;background:#fff8f8}.mc.hi .mv{color:#e8272a}
.box{background:#f8fafc;border-radius:8px;padding:13px 16px;margin-bottom:12px;font-size:12px;line-height:1.7;color:#475569}
.box.strat{background:#f0fdf4;border-left:3px solid #22c55e}
.box.res{background:#fff7ed;border-left:3px solid #f59e0b}
.box-lbl{font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:.8px;margin-bottom:5px}
.box.strat .box-lbl{color:#15803d}.box.res .box-lbl{color:#b45309}
table{width:100%;border-collapse:collapse;font-size:11px}
thead tr{background:#f1f5f9}
thead th{padding:7px 10px;text-align:left;font-weight:600;font-size:9px;text-transform:uppercase;letter-spacing:.4px;color:#64748b}
thead th:not(:first-child){text-align:right}
.recs{margin:0 48px 32px;background:#1e293b;border-radius:12px;padding:22px 26px;color:#fff}
.recs h2{font-size:13px;font-weight:700;margin-bottom:14px;color:#f8fafc}
.rec-item{display:flex;gap:10px;align-items:flex-start;padding:9px 0;border-bottom:1px solid rgba(255,255,255,.08)}
.rec-item:last-child{border-bottom:none}
.rec-badge{padding:2px 8px;border-radius:10px;font-size:9px;font-weight:700;white-space:nowrap}
.rec-badge.alta{background:#dc2626;color:#fff}
.rec-badge.media{background:#d97706;color:#fff}
.rec-badge.baja{background:#0891b2;color:#fff}
.rec-area{font-size:10px;color:#94a3b8;white-space:nowrap;min-width:50px}
.rec-body{flex:1}.rec-txt{font-size:12px;color:#e2e8f0;line-height:1.5}
.rec-reason{font-size:11px;color:#94a3b8;margin-top:3px;line-height:1.4}
.rf{background:#0f172a;color:#64748b;padding:18px 48px;display:flex;justify-content:space-between;align-items:center;font-size:10px;margin-top:32px}
.rf .brand{font-weight:700;color:#fff;font-size:12px}
.np-bar{padding:10px 48px;background:#f1f5f9;display:flex;gap:8px;align-items:center}
.box.obs{background:#eff6ff;border-left:3px solid #3b82f6}
.box.obs .box-lbl{color:#1d4ed8}
.mg5{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-bottom:14px}
.mg6{display:grid;grid-template-columns:repeat(6,1fr);gap:10px;margin-bottom:14px}
.tbl-wrap{overflow-x:auto;margin-bottom:14px}
@media print{
  body{background:#fff}.page{box-shadow:none;max-width:100%}
  .np-bar{display:none!important}
  .sec,.exec,.recs{break-inside:avoid}
  .rh,.rf,.recs,.tc.hi,.mc.hi{-webkit-print-color-adjust:exact;print-color-adjust:exact}
  .box.strat,.box.res,.box.obs{-webkit-print-color-adjust:exact;print-color-adjust:exact}
}
</style>
</head>
<body>
<div class="page">

<div class="np-bar">
  <button onclick="window.print()" style="padding:7px 16px;background:#e8272a;color:#fff;border:none;border-radius:6px;font-size:11px;font-weight:700;cursor:pointer">🖨 Imprimir / Guardar PDF</button>
  <span style="font-size:11px;color:#64748b">En el diálogo de impresión activa <strong>"Gráficos de fondo"</strong> para conservar colores.</span>
</div>

<!-- HEADER -->
<div class="rh">
  <div>
    <?= $logo_tag ?>
    <h1><?= $h($client['name']) ?></h1>
    <p>Reporte de Marketing Digital</p>
  </div>
  <div class="rh-r">
    <div class="per"><?= $h($period_label) ?></div>
    <div class="gen">Generado el <?= $gen_date ?></div>
    <div style="margin-top:8px;font-size:10px;opacity:.5">DIMARK — SuperCerebro</div>
  </div>
</div>

<!-- TOTALES GLOBALES -->
<div class="totals">
  <?php if($total_inv>0): ?><div class="tc hi"><div class="v"><?= rfmt($total_inv) ?></div><div class="l">Inversión total</div></div><?php endif ?>
  <?php if(!empty($meta_data['ok'])): ?>
    <div class="tc"><div class="v"><?= rnum($meta_data['conversions']) ?></div><div class="l">Conv. Meta</div></div>
    <?php if($meta_data['roas']>0): ?><div class="tc"><div class="v"><?= $meta_data['roas'] ?>x</div><div class="l">ROAS Meta</div></div><?php endif ?>
  <?php endif ?>
  <?php if(!empty($google_data['ok'])): ?><div class="tc"><div class="v"><?= rnum($google_data['conversions']) ?></div><div class="l">Conv. Google</div></div><?php endif ?>
  <?php if(!empty($seo_data['ok'])): ?><div class="tc"><div class="v"><?= rnum($seo_data['clicks']) ?></div><div class="l">Clics orgánicos</div></div><?php endif ?>
</div>
<div style="height:24px"></div>

<!-- EXECUTIVE SUMMARY -->
<?php if(!empty($analysis['executive'])): ?>
<div class="exec"><div class="lbl">Resumen Ejecutivo — <?= $h($period_label) ?></div><p><?= nl2br($h($analysis['executive'])) ?></p></div>
<?php endif ?>

<!-- EJECUCIONES DEL PERÍODO -->
<?php if(!empty($analysis['executions'])): ?>
<div style="margin:0 48px 24px;background:#f8fafc;border:1px solid #e2e8f0;border-radius:10px;padding:18px 22px">
  <div style="font-size:9px;font-weight:700;text-transform:uppercase;letter-spacing:1px;color:#64748b;margin-bottom:8px">⚙ Ejecuciones del período</div>
  <p style="font-size:13px;line-height:1.75;color:#334155"><?= nl2br($h($analysis['executions'])) ?></p>
</div>
<?php endif ?>

<!-- ═══════════════════════ META ADS ═══════════════════════ -->
<?php if(!empty($meta_data['ok'])): ?>
<div class="sec">
  <div class="sh"><div class="si m">📘</div><h2>Meta Ads</h2><span class="src">Facebook · Instagram · <?= $h($period_label) ?></span></div>

  <!-- Métricas principales -->
  <div class="mg6">
    <div class="mc hi"><div class="mv"><?= $meta_data['spend_fmt'] ?></div><div class="ml">Inversión</div></div>
    <div class="mc"><div class="mv"><?= rnum($meta_data['reach']) ?></div><div class="ml">Alcance</div></div>
    <div class="mc"><div class="mv"><?= rnum($meta_data['impressions']) ?></div><div class="ml">Impresiones</div></div>
    <div class="mc"><div class="mv"><?= $meta_data['ctr'] ?>%</div><div class="ml">CTR prom.</div></div>
    <div class="mc"><div class="mv"><?= rnum($meta_data['conversions']) ?></div><div class="ml">Conversiones</div></div>
    <div class="mc<?= $meta_data['cpa']>0?' hi':'' ?>"><div class="mv"><?= $meta_data['cpa_fmt'] ?></div><div class="ml">CPA</div></div>
  </div>
  <?php if($meta_data['roas']>0||$meta_data['conv_value']>0): ?>
  <div class="mg" style="grid-template-columns:repeat(2,1fr);margin-bottom:14px">
    <?php if($meta_data['conv_value']>0): ?><div class="mc"><div class="mv"><?= rfmt($meta_data['conv_value']) ?></div><div class="ml">Valor de conversiones</div></div><?php endif ?>
    <?php if($meta_data['roas']>0): ?><div class="mc"><div class="mv"><?= $meta_data['roas'] ?>x</div><div class="ml">ROAS</div></div><?php endif ?>
  </div>
  <?php endif ?>

  <!-- Análisis AVI -->
  <?php if(!empty($analysis['meta_strategy'])): ?>
  <div class="box strat"><div class="box-lbl">🎯 Estrategia ejecutada</div><?= nl2br($h($analysis['meta_strategy'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['meta_results'])): ?>
  <div class="box res"><div class="box-lbl">📊 Análisis de resultados</div><?= nl2br($h($analysis['meta_results'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['meta_observations'])): ?>
  <div class="box obs"><div class="box-lbl">💡 Observaciones y consejos</div><?= nl2br($h($analysis['meta_observations'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['meta_competition'])): ?>
  <div class="box" style="background:#fdf4ff;border-left:3px solid #a855f7"><div class="box-lbl" style="color:#7e22ce">🏆 Análisis de competencia</div><?= nl2br($h($analysis['meta_competition'])) ?></div>
  <?php endif ?>

  <!-- Tabla campañas -->
  <?php if(!empty($meta_data['campaigns'])): ?>
  <div style="font-size:10px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin:14px 0 8px">Detalle de campañas</div>
  <div class="tbl-wrap"><table>
    <thead><tr>
      <th style="min-width:160px">Campaña</th><th>Estado</th><th>Objetivo</th><th>Inversión</th>
      <th>Alcance</th><th>Impr.</th><th>CTR</th><th>Frec.</th><th>CPM</th><th>CPC</th><th>Conv.</th><th>Presupuesto</th>
    </tr></thead>
    <tbody>
    <?php foreach($meta_data['campaigns'] as $c): $td='padding:7px 10px;border-bottom:1px solid #f1f5f9'; ?>
    <tr>
      <td style="<?=$td?>;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"><?= $h($c['name']) ?></td>
      <td style="<?=$td?>"><?= $c['status']==='active'?'<span style="background:#dcfce7;color:#15803d;padding:2px 7px;border-radius:10px;font-size:9px;font-weight:700">Activa</span>':'<span style="background:#fef9c3;color:#a16207;padding:2px 7px;border-radius:10px;font-size:9px;font-weight:700">Pausada</span>' ?></td>
      <td style="<?=$td?>;font-size:10px;color:#64748b"><?= $h(ucfirst($c['objective']??'')) ?></td>
      <td style="<?=$td?>;text-align:right;font-weight:700"><?= $c['spend_fmt'] ?></td>
      <td style="<?=$td?>;text-align:right"><?= $c['reach']>0?rnum($c['reach']):'—' ?></td>
      <td style="<?=$td?>;text-align:right"><?= $c['impressions']>0?rnum($c['impressions']):'—' ?></td>
      <td style="<?=$td?>;text-align:right"><?= $c['ctr']>0?$c['ctr'].'%':'—' ?></td>
      <td style="<?=$td?>;text-align:right"><?= $c['freq']>0?$c['freq']:'—' ?></td>
      <td style="<?=$td?>;text-align:right"><?= $c['cpm']>0?rfmt($c['cpm']):'—' ?></td>
      <td style="<?=$td?>;text-align:right"><?= $c['cpc']>0?rfmt($c['cpc']):'—' ?></td>
      <td style="<?=$td?>;text-align:right;font-weight:700;color:<?=$c['conv']>0?'#15803d':'#94a3b8'?>"><?= $c['conv']>0?rnum($c['conv']):'—' ?></td>
      <td style="<?=$td?>;text-align:right;font-size:10px;color:#64748b"><?= $c['budget'] ?></td>
    </tr>
    <?php endforeach ?>
    </tbody>
  </table></div>
  <?php endif ?>
</div>
<?php endif ?>

<!-- ═══════════════════════ GOOGLE ADS ═══════════════════════ -->
<?php if(!empty($google_data['ok'])): ?>
<div class="sec">
  <div class="sh"><div class="si g">🟢</div><h2>Google Ads</h2><span class="src">Search · Display · <?= $h($period_label) ?></span></div>

  <div class="mg5">
    <div class="mc hi"><div class="mv"><?= $google_data['spend_fmt'] ?></div><div class="ml">Inversión</div></div>
    <div class="mc"><div class="mv"><?= rnum($google_data['clicks']) ?></div><div class="ml">Clics</div></div>
    <div class="mc"><div class="mv"><?= $google_data['ctr'] ?>%</div><div class="ml">CTR</div></div>
    <div class="mc"><div class="mv"><?= rnum($google_data['conversions']) ?></div><div class="ml">Conversiones</div></div>
    <div class="mc<?= $google_data['cpa']>0?' hi':'' ?>"><div class="mv"><?= $google_data['cpa_fmt'] ?></div><div class="ml">CPA</div></div>
  </div>

  <?php if(!empty($analysis['google_strategy'])): ?>
  <div class="box strat"><div class="box-lbl">🎯 Estrategia ejecutada</div><?= nl2br($h($analysis['google_strategy'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['google_results'])): ?>
  <div class="box res"><div class="box-lbl">📊 Análisis de resultados</div><?= nl2br($h($analysis['google_results'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['google_observations'])): ?>
  <div class="box obs"><div class="box-lbl">💡 Observaciones y consejos</div><?= nl2br($h($analysis['google_observations'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['google_competition'])): ?>
  <div class="box" style="background:#fdf4ff;border-left:3px solid #a855f7"><div class="box-lbl" style="color:#7e22ce">🏆 Análisis de competencia · Impression Share</div><?= nl2br($h($analysis['google_competition'])) ?></div>
  <?php endif ?>

  <!-- Tabla campañas -->
  <?php if(!empty($google_data['campaigns'])): ?>
  <div style="font-size:10px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin:14px 0 8px">Detalle de campañas</div>
  <div class="tbl-wrap"><table>
    <thead><tr>
      <th style="min-width:160px">Campaña</th><th>Estado</th><th>Tipo</th><th>Inversión</th>
      <th>Clics</th><th>Impr.</th><th>CTR</th><th>CPC prom.</th><th>Conv.</th><th>IS%</th>
    </tr></thead>
    <tbody>
    <?php foreach($google_data['campaigns'] as $c): $td='padding:7px 10px;border-bottom:1px solid #f1f5f9'; ?>
    <tr>
      <td style="<?=$td?>;max-width:200px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap"><?= $h($c['name']) ?></td>
      <td style="<?=$td?>"><?= $c['status']==='enabled'?'<span style="background:#dcfce7;color:#15803d;padding:2px 7px;border-radius:10px;font-size:9px;font-weight:700">Activa</span>':'<span style="background:#fef9c3;color:#a16207;padding:2px 7px;border-radius:10px;font-size:9px;font-weight:700">Pausada</span>' ?></td>
      <td style="<?=$td?>;font-size:10px;color:#64748b"><?= $h(ucfirst($c['type']??'')) ?></td>
      <td style="<?=$td?>;text-align:right;font-weight:700"><?= $c['spend_fmt'] ?></td>
      <td style="<?=$td?>;text-align:right"><?= rnum($c['clicks']) ?></td>
      <td style="<?=$td?>;text-align:right"><?= rnum($c['impressions']) ?></td>
      <td style="<?=$td?>;text-align:right"><?= $c['ctr']>0?$c['ctr'].'%':'—' ?></td>
      <td style="<?=$td?>;text-align:right"><?= $c['cpc']>0?rfmt($c['cpc']):'—' ?></td>
      <td style="<?=$td?>;text-align:right;font-weight:700;color:<?=$c['conv']>0?'#15803d':'#94a3b8'?>"><?= $c['conv']>0?rnum($c['conv']):'—' ?></td>
      <td style="<?=$td?>;text-align:right;font-size:10px"><?= $c['is']!==null?$c['is'].'%':'—' ?></td>
    </tr>
    <?php endforeach ?>
    </tbody>
  </table></div>
  <?php endif ?>

  <!-- Top Keywords -->
  <?php if(!empty($google_data['keywords'])): ?>
  <div style="font-size:10px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin:16px 0 8px">Top Keywords</div>
  <div class="tbl-wrap"><table>
    <thead><tr><th>Keyword</th><th>Clics</th><th>Impr.</th><th>CTR</th><th>CPC prom.</th><th>Conv.</th></tr></thead>
    <tbody>
    <?php foreach($google_data['keywords'] as $k): $td='padding:6px 10px;border-bottom:1px solid #f1f5f9'; ?>
    <tr>
      <td style="<?=$td?>"><?= $h($k['kw']) ?></td>
      <td style="<?=$td?>;text-align:right"><?= rnum($k['clicks']) ?></td>
      <td style="<?=$td?>;text-align:right"><?= rnum($k['imp']) ?></td>
      <td style="<?=$td?>;text-align:right"><?= $k['imp']>0?round($k['clicks']/$k['imp']*100,2).'%':'—' ?></td>
      <td style="<?=$td?>;text-align:right"><?= $k['cpc']>0?rfmt($k['cpc']):'—' ?></td>
      <td style="<?=$td?>;text-align:right;font-weight:700;color:<?=$k['conv']>0?'#15803d':'#94a3b8'?>"><?= $k['conv']>0?rnum($k['conv']):'—' ?></td>
    </tr>
    <?php endforeach ?>
    </tbody>
  </table></div>
  <?php endif ?>
</div>
<?php endif ?>

<!-- ═══════════════════════ SEO ═══════════════════════ -->
<?php if(!empty($seo_data['ok'])): ?>
<div class="sec">
  <div class="sh"><div class="si s">🔍</div><h2>SEO Orgánico</h2><span class="src">Google Search Console · <?= $h($period_label) ?></span></div>

  <div class="mg">
    <div class="mc hi"><div class="mv"><?= rnum($seo_data['clicks']) ?></div><div class="ml">Clics orgánicos</div></div>
    <div class="mc"><div class="mv"><?= rnum($seo_data['impressions']) ?></div><div class="ml">Impresiones</div></div>
    <div class="mc"><div class="mv"><?= $seo_data['ctr'] ?>%</div><div class="ml">CTR orgánico</div></div>
    <div class="mc"><div class="mv"><?= $seo_data['avg_position'] ?></div><div class="ml">Posición prom.</div></div>
  </div>

  <?php if(!empty($analysis['seo_strategy'])): ?>
  <div class="box strat"><div class="box-lbl">🎯 Contexto y estrategia SEO</div><?= nl2br($h($analysis['seo_strategy'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['seo_results'])): ?>
  <div class="box res"><div class="box-lbl">📊 Análisis de resultados</div><?= nl2br($h($analysis['seo_results'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['seo_observations'])): ?>
  <div class="box obs"><div class="box-lbl">💡 Observaciones y consejos</div><?= nl2br($h($analysis['seo_observations'])) ?></div>
  <?php endif ?>
  <?php if(!empty($analysis['seo_competition'])): ?>
  <div class="box" style="background:#fdf4ff;border-left:3px solid #a855f7"><div class="box-lbl" style="color:#7e22ce">🏆 Análisis de competencia orgánica</div><?= nl2br($h($analysis['seo_competition'])) ?></div>
  <?php endif ?>

  <!-- Top Keywords -->
  <?php if(!empty($seo_data['keywords'])): ?>
  <div style="font-size:10px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin:14px 0 8px">Top Keywords orgánicas</div>
  <div class="tbl-wrap"><table>
    <thead><tr><th>Keyword</th><th>Clics</th><th>Impresiones</th><th>CTR</th><th>Posición</th></tr></thead>
    <tbody>
    <?php foreach($seo_data['keywords'] as $k): $td='padding:7px 10px;border-bottom:1px solid #f1f5f9'; ?>
    <tr>
      <td style="<?=$td?>"><?= $h($k['kw']) ?></td>
      <td style="<?=$td?>;text-align:right;font-weight:700"><?= rnum($k['clicks']) ?></td>
      <td style="<?=$td?>;text-align:right"><?= rnum($k['impressions'] ?? ($k['clicks']>0&&$k['ctr']>0?round($k['clicks']/$k['ctr']*100):0)) ?></td>
      <td style="<?=$td?>;text-align:right"><?= $k['ctr'] ?>%</td>
      <td style="<?=$td?>;text-align:right"><?= $k['pos'] ?></td>
    </tr>
    <?php endforeach ?>
    </tbody>
  </table></div>
  <?php endif ?>

  <!-- Top Páginas -->
  <?php if(!empty($seo_data['pages'])): ?>
  <div style="font-size:10px;font-weight:700;color:#64748b;text-transform:uppercase;letter-spacing:.5px;margin:16px 0 8px">Top Páginas</div>
  <div class="tbl-wrap"><table>
    <thead><tr><th>Página</th><th>Clics</th><th>Impresiones</th><th>CTR</th><th>Posición</th></tr></thead>
    <tbody>
    <?php foreach($seo_data['pages'] as $p): $td='padding:7px 10px;border-bottom:1px solid #f1f5f9'; ?>
    <tr>
      <td style="<?=$td?>;max-width:250px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:11px"><?= $h($p['url']) ?></td>
      <td style="<?=$td?>;text-align:right;font-weight:700"><?= rnum($p['clicks']) ?></td>
      <td style="<?=$td?>;text-align:right"><?= rnum($p['imp']) ?></td>
      <td style="<?=$td?>;text-align:right"><?= $p['ctr'] ?>%</td>
      <td style="<?=$td?>;text-align:right"><?= $p['pos'] ?></td>
    </tr>
    <?php endforeach ?>
    </tbody>
  </table></div>
  <?php endif ?>
</div>
<?php endif ?>

<!-- ═══════════════════════ RECOMENDACIONES ═══════════════════════ -->
<?php if(!empty($analysis['recommendations'])): ?>
<div class="recs">
  <h2>📌 Plan de acción para el próximo mes</h2>
  <?php foreach($analysis['recommendations'] as $rec): ?>
  <div class="rec-item">
    <span class="rec-badge <?= $h($rec['priority']??'media') ?>"><?= strtoupper($h($rec['priority']??'MEDIA')) ?></span>
    <span class="rec-area"><?= strtoupper($h($rec['area']??'')) ?></span>
    <div class="rec-body">
      <div class="rec-txt"><?= $h($rec['action']??'') ?></div>
      <?php if(!empty($rec['reason'])): ?><div class="rec-reason">↳ <?= $h($rec['reason']) ?></div><?php endif ?>
    </div>
  </div>
  <?php endforeach ?>
</div>
<?php endif ?>

<?php if(empty($meta_data['ok'])&&empty($google_data['ok'])&&empty($seo_data['ok'])): ?>
<div style="margin:48px;text-align:center;color:#94a3b8;padding:40px">
  <div style="font-size:32px;margin-bottom:12px">⚠</div>
  <p>No hay credenciales configuradas para este cliente.</p>
</div>
<?php endif ?>

<!-- FOOTER -->
<div class="rf">
  <div><div class="brand">DIMARK</div><div style="margin-top:2px">Agencia de Marketing Digital · SuperCerebro</div></div>
  <div style="text-align:right"><div><?= $h($client['name']) ?> · <?= $h($period_label) ?></div><div style="margin-top:2px">Generado el <?= $gen_date ?></div></div>
</div>

</div>
</body>
</html>
<?php
$html=ob_get_clean();

// Guardar en BD
try {
    $title = $client['name'].' — '.$period_label;
    $stmt=$pdo->prepare("INSERT INTO dm_reports (client_id,period_from,period_to,period_label,html,title,created_at) VALUES (?,?,?,?,?,?,NOW()) ON DUPLICATE KEY UPDATE html=VALUES(html),period_label=VALUES(period_label),title=VALUES(title),created_at=NOW()");
    $stmt->execute([$client_id,$date_from,$date_to,$period_label,$html,$title]);
    $report_id = (int)$pdo->lastInsertId();
    if (!$report_id) {
        $rs=$pdo->prepare("SELECT id FROM dm_reports WHERE client_id=? AND period_from=? AND period_to=? LIMIT 1");
        $rs->execute([$client_id,$date_from,$date_to]);
        $report_id=(int)($rs->fetchColumn()?:0);
    }
} catch(Exception $e){ $report_id=0; }

echo json_encode(['ok'=>true,'html'=>$html,'id'=>$report_id,'period'=>$period_label,
    'meta'=>!empty($meta_data['ok']),'google'=>!empty($google_data['ok']),'seo'=>!empty($seo_data['ok'])]);
