<?php
// cron_sunday_mail.php (debug-safe version)
// Zondag 05:00: stuur sunday_planned mails voor ritten met datum_lossen = vandaag (zondag), zonder voorladen.
// Beveiliging: token vereist. Gebruik ?force=1 voor testen buiten zondag.
// Gebruik ?debug=1 om alleen diagnostics te tonen (geen DB/mails).

header('Content-Type: application/json; charset=utf-8');

// Toon PHP errors in JSON (handig op shared hosting met 500 white screen)
error_reporting(E_ALL);
ini_set('display_errors', '0');

register_shutdown_function(function(){
  $err = error_get_last();
  if($err && in_array($err['type'], [E_ERROR,E_PARSE,E_CORE_ERROR,E_COMPILE_ERROR], true)){
    http_response_code(500);
    echo json_encode([
      'ok'=>false,
      'error'=>'fatal',
      'message'=>$err['message'],
      'file'=>basename($err['file']),
      'line'=>$err['line']
    ], JSON_UNESCAPED_UNICODE);
  }
});

function cron_log_write(array $data): void {
  try{
    $baseDir = dirname(__DIR__) . '/logs';
    if(!is_dir($baseDir)) @mkdir($baseDir, 0775, true);
    $file = $baseDir . '/cron_sunday_mail.log';
    $line = json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    if($line === false) $line = '{"ts":"' . date('c') . '","error":"log_json_encode_failed"}';
    @file_put_contents($file, $line . PHP_EOL, FILE_APPEND | LOCK_EX);
  }catch(Throwable $e){
    // silent
  }
}

function cron_log_context(array $extra = []): array {
  $tz = new DateTimeZone('Europe/Amsterdam');
  return array_merge([
    'ts' => (new DateTimeImmutable('now', $tz))->format('c'),
    'script' => (string)($_SERVER['SCRIPT_NAME'] ?? ''),
    'host' => (string)($_SERVER['HTTP_HOST'] ?? ''),
    'ip' => (string)($_SERVER['REMOTE_ADDR'] ?? ''),
    'query' => (string)($_SERVER['QUERY_STRING'] ?? ''),
  ], $extra);
}


// ─────────────────────────────────────────────────────────────
// Token
// ─────────────────────────────────────────────────────────────
$CRON_TOKEN = (getenv('CRON_TOKEN') ?: (getenv('CRON_TOKEN') ?: getenv('CRON_TOKEN_SUNDAY') ?: '')); // <-- zet dit gelijk aan je token

$token = (string)($_GET['token'] ?? '');
if ($token === '' || $token !== $CRON_TOKEN) {
  cron_log_write(cron_log_context(['event'=>'unauthorized']));
  http_response_code(401);
  echo json_encode(['ok'=>false,'error'=>'unauthorized'], JSON_UNESCAPED_UNICODE);
  exit;
}

$debug = ((string)($_GET['debug'] ?? '') === '1');
$force = ((string)($_GET['force'] ?? '') === '1');
$dry   = ((string)($_GET['dry'] ?? '') === '1');

$tz = new DateTimeZone('Europe/Amsterdam');
$now = new DateTimeImmutable('now', $tz);
$today = $now->format('Y-m-d');

// Compute install prefix from SCRIPT_NAME.
// Example: /transportplanning.bak/tpapi/cron_sunday_mail.php -> prefix /transportplanning.bak
$scriptName = (string)($_SERVER['SCRIPT_NAME'] ?? '');
$dir = rtrim(str_replace('\\','/', dirname($scriptName)), '/');
$prefix = '';
if (substr($dir, -6) === '/tpapi') {
  $prefix = substr($dir, 0, -6);
} else {
  $prefix = $dir;
}

// Diagnostics mode (no DB, no mail)
if($debug){
  cron_log_write(cron_log_context(['event'=>'debug','force'=>$force,'dry'=>$dry,'today'=>$today]));
  echo json_encode([
    'ok'=>true,
    'debug'=>true,
    'today'=>$today,
    'is_sunday'=>((int)$now->format('N')===7),
    'force'=>$force,
    'php'=>PHP_VERSION,
    'script_name'=>$scriptName,
    'prefix'=>$prefix,
    'allow_url_fopen'=>ini_get('allow_url_fopen'),
    'has_curl'=>function_exists('curl_init'),
  ], JSON_UNESCAPED_UNICODE);
  exit;
}

// Only run on Sunday unless force=1
if(!$force && (int)$now->format('N') !== 7){
  cron_log_write(cron_log_context(['event'=>'skip_not_sunday','today'=>$today]));
  echo json_encode(['ok'=>true,'skipped'=>'not_sunday','today'=>$today], JSON_UNESCAPED_UNICODE);
  exit;
}

require_once __DIR__ . '/../api/db.php'; // provides $pdo (PDO)

// Select candidates (assumes mail_sunday_sent_at exists)
// For combinatieritten we group all rows by combo_id and send them in one call with send_all_combo=1.
$sql = "
  SELECT id, combo_id, losbestemming
  FROM planned_transports
  WHERE datum_lossen = :today
    AND (datum_laden IS NULL OR datum_laden = '' OR datum_laden = datum_lossen)
    AND (tijd_lossen IS NOT NULL AND tijd_lossen <> '')
    AND (mail_sunday_sent_at IS NULL)
  ORDER BY combo_id ASC, id ASC
";
$stmt = $pdo->prepare($sql);
$stmt->execute([':today'=>$today]);
$candidateRows = $stmt->fetchAll(PDO::FETCH_ASSOC) ?: [];

$tasks = [];
$comboGroups = [];
foreach($candidateRows as $row){
  $id = (int)($row['id'] ?? 0);
  $comboId = (int)($row['combo_id'] ?? 0);
  if($id <= 0) continue;
  if($comboId > 0){
    if(!isset($comboGroups[$comboId])){
      $comboGroups[$comboId] = ['combo_id'=>$comboId, 'representative_id'=>$id, 'ids'=>[]];
    }
    if($id < (int)$comboGroups[$comboId]['representative_id']){
      $comboGroups[$comboId]['representative_id'] = $id;
    }
    $comboGroups[$comboId]['ids'][] = $id;
  }else{
    $tasks[] = ['id'=>$id, 'combo_id'=>0, 'ids'=>[$id], 'send_all_combo'=>false];
  }
}
foreach($comboGroups as $grp){
  $tasks[] = [
    'id'=>(int)$grp['representative_id'],
    'combo_id'=>(int)$grp['combo_id'],
    'ids'=>array_values(array_unique(array_map('intval', $grp['ids']))),
    'send_all_combo'=>true
  ];
}
usort($tasks, function($a, $b){
  return ((int)$a['id'] <=> (int)$b['id']);
});

// POST helper (no curl needed)
function post_json($url, $data){
  $payload = json_encode($data);
  $headers = "Content-Type: application/json\r\nAccept: application/json\r\n";
  $ctx = stream_context_create([
    'http' => [
      'method'  => 'POST',
      'header'  => $headers,
      'content' => $payload,
      'timeout' => 30,
    ]
  ]);
  $resp = @file_get_contents($url, false, $ctx);

  $code = 0;
  if(isset($http_response_header) && is_array($http_response_header)){
    foreach($http_response_header as $h){
      if(preg_match('#^HTTP/\S+\s+(\d{3})#', $h, $mm)){
        $code = (int)$mm[1];
        break;
      }
    }
  }

  $json = null;
  if(is_string($resp) && $resp !== '') $json = json_decode($resp, true);

  return ['code'=>$code,'json'=>$json,'raw'=>is_string($resp)?$resp:''];
}

// endpoint same install
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
$host = $_SERVER['HTTP_HOST'] ?? 'localhost';
$base = $scheme . '://' . $host;
$endpoint = $base . '/api/customer_delay_mail.php?action=send';

function mark_sent_ids(PDO $pdo, array $ids): void {
  $ids = array_values(array_unique(array_map('intval', $ids)));
  $ids = array_values(array_filter($ids, fn($v)=>$v>0));
  if(!$ids) return;
  $ph = implode(',', array_fill(0, count($ids), '?'));
  $sql = "UPDATE planned_transports SET mail_sunday_sent_at = NOW() WHERE id IN ($ph)";
  $st = $pdo->prepare($sql);
  $st->execute($ids);
}


$out = [
  'ok'=>true,
  'today'=>$today,
  'endpoint'=>$endpoint,
  'count'=>count($candidateRows),
  'task_count'=>count($tasks),
  'sent'=>0,
  'dry'=>$dry,
  'errors'=>0,
  'items'=>[],
];

$taskIndex = 0;
foreach($tasks as $task){
  $id = (string)($task['id'] ?? '');
  if($taskIndex > 0) usleep(1500000);
  $taskIndex++;
  $comboId = (int)($task['combo_id'] ?? 0);
  $taskIds = array_values(array_unique(array_map('intval', (array)($task['ids'] ?? []))));
  $sendAllCombo = !empty($task['send_all_combo']);

  if($dry){
    cron_log_write(cron_log_context(['event'=>'dry_task','id'=>$id,'combo_id'=>$comboId,'send_all_combo'=>$sendAllCombo]));
    $out['items'][] = $sendAllCombo
      ? ['id'=>$id, 'combo_id'=>$comboId, 'ids'=>$taskIds, 'would_send'=>true, 'send_all_combo'=>true]
      : ['id'=>$id, 'would_send'=>true];
    continue;
  }

  $payload = ['id'=>$id, 'template'=>'sunday_planned', 'cron_token'=>(getenv('CRON_TOKEN') ?: (getenv('CRON_TOKEN') ?: getenv('CRON_TOKEN_SUNDAY') ?: ''))];
  if($sendAllCombo) $payload['send_all_combo'] = 1;

  $r = post_json($endpoint, $payload);
  $json = is_array($r['json']) ? $r['json'] : [];
  $alreadySent = (($json['skipped'] ?? '') === 'already_sent');
  $retryable = (!empty($json['retryable']) || (($r['code'] ?? 0) == 429) || (strpos(mb_strtolower((string)($json['error'] ?? ($json['message'] ?? '')), 'UTF-8'), 'rate limit') !== false));
  $ok = ($r['code'] >= 200 && $r['code'] < 300 && is_array($json) && (($json['sent'] ?? false) === true));

  if($ok){
    // For combo mails, prefer marking only the rows that were actually sent.
    $markIds = $taskIds;
    if($sendAllCombo && !empty($json['results']) && is_array($json['results'])){
      $sentIds = [];
      foreach($json['results'] as $res){
        if(empty($res['sent'])) continue;
        $rid = (int)($res['transport_id'] ?? 0);
        if($rid > 0) $sentIds[] = $rid;
      }
      if($sentIds) $markIds = array_values(array_unique($sentIds));
    }
    mark_sent_ids($pdo, $markIds);
    $out['sent'] += count($markIds);
    $out['items'][] = $sendAllCombo
      ? ['id'=>$id,'combo_id'=>$comboId,'ids'=>$markIds,'sent'=>true,'subject'=>($json['subject'] ?? null),'results'=>($json['results'] ?? null)]
      : ['id'=>$id,'sent'=>true,'subject'=>($json['subject'] ?? null)];
  }elseif($alreadySent){
    $out['items'][] = [
      'id'=>$id,
      'combo_id'=>$comboId ?: null,
      'ids'=>$taskIds,
      'sent'=>false,
      'skipped'=>'already_sent',
      'results'=>($json['results'] ?? null),
    ];
  }elseif($retryable){
    $out['errors']++;
    $out['items'][] = [
      'id'=>$id,
      'combo_id'=>$comboId ?: null,
      'ids'=>$taskIds,
      'sent'=>false,
      'retryable'=>true,
      'http'=>$r['code'],
      'error'=>($json['error'] ?? ($json['message'] ?? 'retry_later')),
      'raw'=>substr((string)$r['raw'], 0, 500),
      'results'=>($json['results'] ?? null),
    ];
  }else{
    $out['errors']++;
    $out['items'][] = [
      'id'=>$id,
      'combo_id'=>$comboId ?: null,
      'ids'=>$taskIds,
      'sent'=>false,
      'http'=>$r['code'],
      'error'=>($json['error'] ?? ($json['message'] ?? 'request_failed')),
      'raw'=>substr((string)$r['raw'], 0, 500),
      'results'=>($json['results'] ?? null),
    ];
  }
}

cron_log_write(cron_log_context(['event'=>'end_run','today'=>$today,'task_count'=>count($tasks),'sent'=>$out['sent'] ?? 0,'errors'=>$out['errors'] ?? 0,'dry'=>$dry]));
echo json_encode($out, JSON_UNESCAPED_UNICODE);
