<?php

require_once __DIR__ . '/../api-handling/fmp_client.php';

/**
 * Korrelationen (inkl. Sector-ETF + Lead/Lag) für ein Symbol.
 *
 * Rückgabe:
 * [
 *   'symbol'     => 'AAPL',
 *   'windows'    => [30,90,252],
 *   'benchmarks' => [ ['symbol'=>'SPY','corr'=>['30'=>..,'90'=>..,'252'=>..]], ... ],
 *   'rolling'    => [ ['date'=>'YYYY-MM-DD','corr'=>..], ... ],            // vs SPY (90d)
 *   'meta'       => [ 'sector' => 'Information Technology', 'sector_etf'=>'XLK' ],
 *   'leadlag'    => [ 'maxLag'=>5, 'bestLag'=>-1, 'bestCorr'=>0.87 ]       // vs SPY (±maxLag)
 * ]
 */
function bewertung_korrelationen_run(string $symbol, array $opts = []): array
{
	$symbol = strtoupper(trim($symbol));
	if ($symbol === '' || !preg_match('/^[A-Z0-9\.\^\-]{1,15}$/', $symbol)) {
		return ['error' => 'Ungültiges Symbol.'];
	}

	// Optionen
	$windows        = $opts['windows'] ?? [30, 90, 252];
	$rollingWindow  = (int)($opts['rolling'] ?? 90);
	$yearsLookback  = (int)($opts['years'] ?? 3);
	$maxLag         = (int)($opts['maxLag'] ?? 5); // Lead/Lag in Tagen (±)

	$from = (new DateTime("-{$yearsLookback} years"))->format('Y-m-d');
	$to   = (new DateTime('now'))->format('Y-m-d');

	// Basis-Benchmarks (ETF/Proxys)
	$benchmarks = $opts['benchmarks'] ?? [
		'SPY','QQQ','IWM','EWG','FEZ','EFA','EEM','TLT','HYG','UUP','GLD','USO','VIXY'
	];

	// --- Sector→ETF Mapping (robust, mit Synonymen)
	$sectorSynMap = [
	  'communication services' => 'XLC', 'communications services' => 'XLC',
	  'consumer discretionary' => 'XLY', 'consumer cyclical' => 'XLY',
	  'consumer staples'       => 'XLP', 'consumer defensive'     => 'XLP',
	  'energy' => 'XLE',
	  'financials' => 'XLF', 'financial services' => 'XLF',
	  'health care' => 'XLV', 'healthcare' => 'XLV',
	  'industrials' => 'XLI',
	  'information technology' => 'XLK', 'technology' => 'XLK',
	  'materials' => 'XLB', 'basic materials' => 'XLB',
	  'real estate' => 'XLRE',
	  'utilities' => 'XLU',
	];
	
	// ---- Requests bündeln (alles via fmp_multi)
	// Erwartete Registry-Keys:
	//  - 'profile' → /api/v3/profile/{symbol}
	//  - 'historical_price_full' → /api/v3/historical-price-full/{symbol}
	$requests = [];

	// Profil des Zielsymbols (für Sektor-ETF)
	$requests["{$symbol}.profile"] = [
		'key'   => 'profile',
		'vars'  => ['symbol' => $symbol],
		'query' => []
	];

	// Historie des Zielsymbols
	$requests["{$symbol}.hist"] = [
		'key'   => 'historical_price_full',
		'vars'  => ['symbol' => $symbol],
		'query' => ['from' => $from, 'to' => $to, 'serietype' => 'line'],
	];

	// Historien der Benchmarks – Sector-ETF fügen wir ggf. gleich noch hinzu
	foreach ($benchmarks as $b) {
		$requests["{$b}.hist"] = [
			'key'   => 'historical_price_full',
			'vars'  => ['symbol' => $b],
			'query' => ['from' => $from, 'to' => $to, 'serietype' => 'line'],
		];
	}

	$raw = fmp_multi($requests, 20);

	// --- Helfer
	$extractProfile = function($payload): array {
		// häufig: [ { ...profile... } ]
		if (is_array($payload)) {
			if (isset($payload[0]) && is_array($payload[0])) return $payload[0];
			if (isset($payload['sector'])) return $payload;
		}
		return [];
	};

	$extractHistorical = function($payload): array {
		if (!is_array($payload)) return [];
		if (isset($payload['historical']) && is_array($payload['historical'])) return $payload['historical'];
		if (isset($payload[0]['historical']) && is_array($payload[0]['historical'])) return $payload[0]['historical'];
		return [];
	};

	$toReturns = function(array $hist): array {
		usort($hist, fn($a,$b)=> strcmp($a['date'] ?? '', $b['date'] ?? ''));
		$ret = []; $prev = null;
		foreach ($hist as $row) {
			if (!isset($row['date'], $row['close'])) continue;
			$c = (float)$row['close'];
			if ($prev !== null && $c > 0 && $prev > 0) $ret[$row['date']] = log($c/$prev);
			$prev = $c;
		}
		return $ret;
	};

	$align = function(array $a, array $b): array {
		$dates = array_values(array_intersect(array_keys($a), array_keys($b)));
		sort($dates);
		$xa=[]; $xb=[];
		foreach ($dates as $d){ $xa[] = $a[$d]; $xb[] = $b[$d]; }
		return [$xa,$xb,$dates];
	};

	$corr = function(array $x, array $y): ?float {
		$n = count($x);
		if ($n < 3 || $n !== count($y)) return null;
		$mx = array_sum($x)/$n; $my = array_sum($y)/$n;
		$num=0; $dx2=0; $dy2=0;
		for ($i=0;$i<$n;$i++){
			$dx=$x[$i]-$mx; $dy=$y[$i]-$my;
			$num += $dx*$dy; $dx2 += $dx*$dx; $dy2 += $dy*$dy;
		}
		if ($dx2<=0 || $dy2<=0) return null;
		return $num / sqrt($dx2*$dy2);
	};

	// Cross-Corr vs SPY: lag>0 ⇒ Aktie folgt SPY um "lag" Tage; lag<0 ⇒ Aktie führt SPY
	$bestLagCorr = function(array $xs, array $ys, int $maxLag, callable $corr): array {
		$best = ['bestLag'=>0, 'bestCorr'=>null, 'maxLag'=>$maxLag];
		$n = min(count($xs), count($ys));
		if ($n < 10) return $best;

		for ($lag=-$maxLag; $lag<=$maxLag; $lag++) {
			if ($lag === 0) {
				$c = $corr($xs, $ys);
			} elseif ($lag > 0) {
				// Aktie laggt: vergleiche xs[lag:] mit ys[0: n-lag]
				$c = $corr(array_slice($xs, $lag), array_slice($ys, 0, $n - $lag));
			} else { // $lag < 0  → Aktie führt: xs[0:n+lag] vs ys[-lag:]
				$k = -$lag;
				$c = $corr(array_slice($xs, 0, $n - $k), array_slice($ys, $k));
			}
			if ($c === null) continue;
			if ($best['bestCorr'] === null || abs($c) > abs($best['bestCorr'])) {
				$best = ['bestLag'=>$lag, 'bestCorr'=>$c, 'maxLag'=>$maxLag];
			}
		}
		return $best;
	};
	
	$variance = function(array $x): ?float {
		$n = count($x); if ($n < 2) return null;
		$m = array_sum($x)/$n; $s=0;
		foreach ($x as $v) { $d = $v - $m; $s += $d*$d; }
		return $s/($n-1);
	};
	$covariance = function(array $x, array $y) use ($variance): ?float {
		$n = count($x); if ($n < 2 || $n !== count($y)) return null;
		$mx = array_sum($x)/$n; $my = array_sum($y)/$n; $s=0;
		for ($i=0;$i<$n;$i++){ $s += ($x[$i]-$mx)*($y[$i]-$my); }
		return $s/($n-1);
	};
	$stddev = function(array $x) use ($variance): ?float {
		$v = $variance($x); return $v!==null ? sqrt($v) : null;
	};

	// --- Profil auswerten (Sector → ETF ergänzen, falls vorhanden)
	$profile = $extractProfile($raw["{$symbol}.profile"] ?? []);
	$sector  = isset($profile['sector']) && is_string($profile['sector']) ? $profile['sector'] : null;
	$sectorKey = $sector ? strtolower(preg_replace('/\s+/', ' ', trim($sector))) : null;
	$sectorEtf = $sectorKey && isset($sectorSynMap[$sectorKey]) ? $sectorSynMap[$sectorKey] : null;

	if ($sectorEtf && !in_array($sectorEtf, $benchmarks, true)) {
		$benchmarks[] = $sectorEtf;
		if (!isset($raw["{$sectorEtf}.hist"])) {
			$more = fmp_multi([
				"{$sectorEtf}.hist" => [
					'key'   => 'historical_price_full',
					'vars'  => ['symbol' => $sectorEtf],
					'query' => ['from'=>$from,'to'=>$to,'serietype'=>'line']
				]
			], 20);
			$raw = array_merge($raw, $more);
		}
	}
	
	// Peers laden (falls Registry jetzt stock_screener hat)
	$peerSyms = [];
	if ($sector) {
	  $screener = fmp_multi([
		'peers.screener' => [
		  'key' => 'stock_screener',
		  'vars'=> [],
		  'query' => ['sector' => $sector, 'limit' => 15]
		]
	  ], 20);
	
	  $peerRows = $screener['peers.screener'] ?? [];
	  // Symbole extrahieren (FMP liefert meist array of objects)
	  $peerSyms = array_values(array_unique(array_filter(array_map(
		fn($r)=> $r['symbol'] ?? null, $peerRows
	  ))));
	
	  // Zielsymbol selbst entfernen & begrenzen (8–12 sind gut fürs Limit)
	  $peerSyms = array_values(array_diff($peerSyms, [$symbol]));
	  $peerSyms = array_slice($peerSyms, 0, 8);
	
	  // Historien der Peers nachladen (falls noch nicht geladen)
	  if ($peerSyms) {
		$reqPeers = [];
		foreach ($peerSyms as $ps) {
		  $reqPeers["{$ps}.hist"] = [
			'key'   => 'historical_price_full',
			'vars'  => ['symbol' => $ps],
			'query' => ['from'=>$from, 'to'=>$to, 'serietype'=>'line']
		  ];
		}
		$more = fmp_multi($reqPeers, 20);
		$raw  = array_merge($raw, $more);
	  }
	}

	// --- Ziel-Returns
	$histTarget = $extractHistorical($raw["{$symbol}.hist"] ?? []);
	if (!$histTarget) return ['error' => "Keine Historie für {$symbol} gefunden."];
	$retTarget  = $toReturns($histTarget);
	
	// Ergebnis-Struktur JETZT initialisieren
	$result = [
	  'symbol'     => $symbol,
	  'windows'    => array_values($windows),
	  'benchmarks' => [],
	  'rolling'    => [],
	  'meta'       => ['sector'=>$sector, 'sector_etf'=>$sectorEtf],
	  'leadlag'    => null,
	  'risk'       => null
	];
	
	// --- Benchmarks berechnen + Rolling/Beta/Vol vs SPY
	$spyAligned = null; // für Lead/Lag
	foreach ($benchmarks as $bSym) {
	  $histB = $extractHistorical($raw["{$bSym}.hist"] ?? []);
	  if (!$histB) continue;
	
	  $retB = $toReturns($histB);
	  [$xa,$xb,$dates] = $align($retTarget, $retB);
	  if (count($dates) < 30) continue;
	
	  // Fenster-Korrelationen
	  $vals = [];
	  foreach ($windows as $w) {
		$w = (int)$w;
		if (count($dates) < $w) { $vals[(string)$w] = null; continue; }
		$vals[(string)$w] = $corr(
		  array_slice($xa, -$w),
		  array_slice($xb, -$w)
		);
	  }
	  $result['benchmarks'][] = ['symbol'=>$bSym, 'corr'=>$vals];
	
	  if ($bSym === 'SPY') {
		// Rolling 90
		$result['rolling'] = (function($X,$Y,$D,$win) use ($corr) {
		  $out=[]; $n=count($D);
		  for ($i=$win-1; $i<$n; $i++){
			$cx = array_slice($X, $i-$win+1, $win);
			$cy = array_slice($Y, $i-$win+1, $win);
			$c = $corr($cx,$cy);
			if ($c !== null) $out[] = ['date'=>$D[$i], 'corr'=>$c];
		  }
		  return $out;
		})($xa,$xb,$dates,$rollingWindow);
	
		// ---- Beta & Volatilität (annualisiert) vs SPY
		$risk = ['beta'=>[], 'vol'=>['asset'=>[], 'spy'=>[], 'rel'=>[]]];
		foreach ($windows as $w) {
		  $w = (int)$w;
		  if (count($dates) < $w) {
			$risk['beta'][(string)$w] = null;
			$risk['vol']['asset'][(string)$w] = null;
			$risk['vol']['spy'][(string)$w]   = null;
			$risk['vol']['rel'][(string)$w]   = null;
			continue;
		  }
		  $ax = array_slice($xa, -$w);
		  $mx = array_slice($xb, -$w);
	
		  $varM = $variance($mx);
		  $cov  = $covariance($ax, $mx);
		  $beta = ($varM!==null && $varM>0 && $cov!==null) ? ($cov / $varM) : null;
	
		  $sdA  = $stddev($ax);
		  $sdM  = $stddev($mx);
		  $ann  = sqrt(252);
		  $volA = ($sdA!==null) ? $sdA * $ann : null; // in %? → dann *100
		  $volM = ($sdM!==null) ? $sdM * $ann : null; // in %? → dann *100
		  $rel  = ($volA!==null && $volM!==null && $volM>0) ? ($volA / $volM) : null;
	
		  $key = (string)$w;
		  $risk['beta'][$key]            = $beta;
		  $risk['vol']['asset'][$key]    = $volA;
		  $risk['vol']['spy'][$key]      = $volM;
		  $risk['vol']['rel'][$key]      = $rel;
		}
		$result['risk'] = $risk;
	
		$spyAligned = [$xa,$xb];
	  }
	}
	
	// --- Lead/Lag vs SPY
	if ($spyAligned && $maxLag > 0) {
	  [$xa,$xb] = $spyAligned;
	  $result['leadlag'] = $bestLagCorr($xa,$xb,$maxLag,$corr);
	}
	
	return $result;

}