<?php
/**
 * Simple CLI script to fetch active Meta Ads insights for:
 * campaign, adset, ad levels for the last N days (default 30).
 *
 * Usage:
 * php tools/meta-ads-active-insights.php --token=TOKEN --account=act_123456789 --days=30
 * php tools/meta-ads-active-insights.php --token=TOKEN --account=123456789 --output=tmp/meta_insights.json
 *
 * You can also use env vars:
 * META_ACCESS_TOKEN
 * META_AD_ACCOUNT_ID
 */

if ( PHP_SAPI !== 'cli' )
{
  fwrite( STDERR, "This script must be run from CLI.\n" );
  exit( 1 );
}

$options = getopt( '', [
  'token::',
  'account::',
  'days::',
  'api-version::',
  'output::',
  'help::'
] );

if ( isset( $options['help'] ) )
{
  echo "Usage:\n";
  echo "  php tools/meta-ads-active-insights.php --token=TOKEN --account=act_123 --days=30\n";
  echo "  php tools/meta-ads-active-insights.php --token=TOKEN --account=123 --output=tmp/meta.json\n";
  echo "\n";
  echo "Options:\n";
  echo "  --token        Meta access token (or META_ACCESS_TOKEN env)\n";
  echo "  --account      Ad account id, with or without act_ prefix (or META_AD_ACCOUNT_ID env)\n";
  echo "  --days         Number of days back, default 30\n";
  echo "  --api-version  Graph API version, default v25.0\n";
  echo "  --output       Optional output JSON file path\n";
  exit( 0 );
}

$token = trim( (string) ( $options['token'] ?? getenv( 'META_ACCESS_TOKEN' ) ?? '' ) );
$account_id = trim( (string) ( $options['account'] ?? getenv( 'META_AD_ACCOUNT_ID' ) ?? '' ) );
$days = (int) ( $options['days'] ?? 30 );
$api_version = trim( (string) ( $options['api-version'] ?? 'v25.0' ) );
$output = trim( (string) ( $options['output'] ?? '' ) );

if ( $token === '' )
{
  fwrite( STDERR, "Missing token. Use --token or META_ACCESS_TOKEN.\n" );
  exit( 1 );
}

if ( $account_id === '' )
{
  fwrite( STDERR, "Missing ad account id. Use --account or META_AD_ACCOUNT_ID.\n" );
  exit( 1 );
}

if ( strpos( $account_id, 'act_' ) !== 0 )
{
  $account_id = 'act_' . preg_replace( '/\D+/', '', $account_id );
}

if ( $account_id === 'act_' )
{
  fwrite( STDERR, "Invalid ad account id.\n" );
  exit( 1 );
}

if ( $days < 1 )
{
  $days = 1;
}

$since = date( 'Y-m-d', strtotime( '-' . ( $days - 1 ) . ' days' ) );
$until = date( 'Y-m-d' );
$base_url = 'https://graph.facebook.com/' . rawurlencode( $api_version ) . '/' . rawurlencode( $account_id ) . '/insights';

$levels = [
  'campaign' => [
    'fields' => 'account_id,campaign_id,campaign_name,spend,impressions,clicks,ctr,cpc,action_values,purchase_roas,date_start,date_stop',
    'filtering_field' => 'campaign.effective_status'
  ],
  'adset' => [
    'fields' => 'account_id,campaign_id,campaign_name,adset_id,adset_name,spend,impressions,clicks,ctr,cpc,action_values,purchase_roas,date_start,date_stop',
    'filtering_field' => 'adset.effective_status'
  ],
  'ad' => [
    'fields' => 'account_id,campaign_id,campaign_name,adset_id,adset_name,ad_id,ad_name,spend,impressions,clicks,ctr,cpc,action_values,purchase_roas,date_start,date_stop',
    'filtering_field' => 'ad.effective_status'
  ]
];

$result = [
  'meta' => [
    'account_id' => $account_id,
    'api_version' => $api_version,
    'days' => $days,
    'since' => $since,
    'until' => $until,
    'generated_at' => date( 'c' )
  ],
  'campaign' => [],
  'adset' => [],
  'ad' => [],
  'summary' => []
];

try
{
  foreach ( $levels as $level => $cfg )
  {
    fwrite( STDERR, "Fetching level: {$level}\n" );

    $params = [
      'access_token' => $token,
      'level' => $level,
      'fields' => $cfg['fields'],
      'time_increment' => 1,
      'time_range' => json_encode( [ 'since' => $since, 'until' => $until ] ),
      'filtering' => json_encode( [
        [
          'field' => $cfg['filtering_field'],
          'operator' => 'IN',
          'value' => [ 'ACTIVE' ]
        ]
      ] ),
      'limit' => 500
    ];

    $rows = fetch_all_pages( $base_url, $params );
    $result[ $level ] = $rows;
    $result['summary'][ $level . '_rows' ] = count( $rows );
  }
}
catch ( Exception $e )
{
  fwrite( STDERR, "Error: " . $e -> getMessage() . "\n" );
  exit( 1 );
}

$json = json_encode( $result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_PRETTY_PRINT );

if ( $json === false )
{
  fwrite( STDERR, "Failed to encode JSON output.\n" );
  exit( 1 );
}

if ( $output !== '' )
{
  $output_dir = dirname( $output );
  if ( $output_dir !== '' && $output_dir !== '.' && !is_dir( $output_dir ) )
  {
    if ( !mkdir( $output_dir, 0775, true ) && !is_dir( $output_dir ) )
    {
      fwrite( STDERR, "Failed to create output directory: {$output_dir}\n" );
      exit( 1 );
    }
  }

  if ( file_put_contents( $output, $json ) === false )
  {
    fwrite( STDERR, "Failed to write output file: {$output}\n" );
    exit( 1 );
  }

  fwrite( STDERR, "Saved: {$output}\n" );
}
else
{
  echo $json . PHP_EOL;
}

exit( 0 );

function fetch_all_pages( $url, $params = null )
{
  $all_rows = [];
  $next_url = $url;
  $next_params = $params;

  while ( $next_url )
  {
    $payload = request_json( $next_url, $next_params );

    if ( isset( $payload['data'] ) && is_array( $payload['data'] ) )
    {
      foreach ( $payload['data'] as $row )
      {
        $all_rows[] = $row;
      }
    }

    $next_url = '';
    $next_params = null;

    if ( isset( $payload['paging']['next'] ) && is_string( $payload['paging']['next'] ) )
    {
      $next_url = $payload['paging']['next'];
    }
  }

  return $all_rows;
}

function request_json( $url, $params = null )
{
  if ( is_array( $params ) )
  {
    $query = http_build_query( $params );
    $url .= ( strpos( $url, '?' ) === false ? '?' : '&' ) . $query;
  }

  $ch = curl_init( $url );
  curl_setopt_array( $ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_SSL_VERIFYPEER => true,
    CURLOPT_CONNECTTIMEOUT => 20,
    CURLOPT_TIMEOUT => 120
  ] );

  $response = curl_exec( $ch );
  $curl_error = curl_error( $ch );
  $http_code = (int) curl_getinfo( $ch, CURLINFO_HTTP_CODE );
  curl_close( $ch );

  if ( $response === false )
  {
    throw new Exception( 'cURL error: ' . $curl_error );
  }

  $decoded = json_decode( $response, true );
  if ( !is_array( $decoded ) )
  {
    throw new Exception( 'Invalid JSON response. HTTP ' . $http_code . '. Body: ' . substr( (string) $response, 0, 1000 ) );
  }

  if ( isset( $decoded['error'] ) )
  {
    $message = (string) ( $decoded['error']['message'] ?? 'Unknown API error' );
    $code = (string) ( $decoded['error']['code'] ?? '' );
    $subcode = (string) ( $decoded['error']['error_subcode'] ?? '' );
    throw new Exception( 'Meta API error: ' . $message . ' (code: ' . $code . ', subcode: ' . $subcode . ')' );
  }

  if ( $http_code >= 400 )
  {
    throw new Exception( 'HTTP error ' . $http_code . '. Body: ' . substr( (string) $response, 0, 1000 ) );
  }

  return $decoded;
}
