<?php

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class HBDEV_Budget_REST {
	public static function register_routes() {
		register_rest_route( 'hbdev-bookings/v1', '/stats', [
			'methods'             => 'GET',
			'callback'            => [ __CLASS__, 'stats' ],
			'permission_callback' => function () {
				return current_user_can( 'manage_bookings' );
			},
			'args'                => [
				'month' => [
					'description' => 'Monat im Format YYYY-MM',
					'type'        => 'string',
					'required'    => false,
				],
			],
		] );
	}

	public static function stats( WP_REST_Request $req ) {
		$ym = HBDEV_Budget_Helpers::sanitize_ym( $req->get_param( 'month' ) );
		$user_id = get_current_user_id();
		$cache_key = HBDEV_Budget_Helpers::stats_cache_key($ym, $user_id);
		$cached = get_transient($cache_key);
		if (is_array($cached)) {
			// Validate cache schema: ensure new KPI fields exist and top level is versioned; otherwise rebuild
			$has_open_close = isset($cached['kpi']) && is_array($cached['kpi'])
				&& array_key_exists('opening_balance', $cached['kpi'])
				&& array_key_exists('closing_balance', $cached['kpi']);
			$has_top_level2 = isset($cached['top_expense_level']) && (int)$cached['top_expense_level'] === 2;
			if ($has_open_close && $has_top_level2) {
				return new WP_REST_Response($cached, 200);
			}
			// fallthrough: cached data is outdated, continue to recompute below
		}

		[ $start, $end ] = HBDEV_Budget_Helpers::month_bounds( $ym );

		// Query: Buchungen im Zeitraum (Meta: booking_date (YYYY-MM-DD), booking_amount (float))
		$q = new WP_Query( [
			'post_type'      => 'booking',
			'post_status'    => [ 'publish' ],
			'posts_per_page' => - 1,
			'no_found_rows'  => true,
			'author'         => $user_id,
			'meta_query'     => [
				'relation' => 'AND',
				[
					'key'     => 'booking_date',
					'value'   => [ $start->format( 'Y-m-d' ), $end->format( 'Y-m-d' ) ],
					'type'    => 'DATE',
					'compare' => 'BETWEEN',
				],
				[
					'key'     => 'booking_amount',
					'compare' => 'EXISTS',
				],
			],
			'fields'         => 'ids',
		] );

		$total   = 0.0;
		$income  = 0.0;
		$expense = 0.0;
		$cats    = [];     // ['Pfad/Name' => ['sum'=>..,'count'=>..]]
		$daily   = [];    // 'YYYY-MM-DD' => ['in'=>..,'out'=>..]
		$expenseLevel2 = []; // Aggregation Ebene 2 unter Ausgaben: ['Level2Name' => ['sum'=>..,'count'=>..]]

		// Init daily buckets for den ganzen Monat
		$cursor = $start;
		while ( $cursor <= $end ) {
			$daily[ $cursor->format( 'Y-m-d' ) ] = [ 'in' => 0.0, 'out' => 0.0 ];
			$cursor                              = $cursor->modify( '+1 day' );
		}

		// Ermittle Ausgaben-Wurzelbegriff dynamisch (für Ebene-2-Aggregation)
		$expense_root_term = get_term_by( 'slug', 'ausgaben', 'booking_type' );
		$expense_root_name = ( $expense_root_term && ! is_wp_error( $expense_root_term ) && ! empty( $expense_root_term->name ) )
			? $expense_root_term->name
			: 'Ausgaben';

		foreach ( $q->posts as $pid ) {
			$amount = (float) get_post_meta( $pid, 'booking_amount', true );
			$date   = get_post_meta( $pid, 'booking_date', true );
			if ( ! isset( $daily[ $date ] ) ) {
				$daily[ $date ] = [ 'in' => 0.0, 'out' => 0.0 ];
			}

			$terms = wp_get_post_terms( $pid, 'booking_type' );
			// Bestimme Top-Level (Einnahmen vs Ausgaben) + baue Pfad
			$top   = 'Unkategorisiert';
			$paths = [];
			$misc_label = __( 'Sonstige', 'hbdev-budget' );

			if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
				foreach ( $terms as $t ) {
					$path = [ $t->name ];
					$root = $t;
					while ( $root->parent ) {
						$root = get_term( $root->parent, 'booking_type' );
						if ( $root && ! is_wp_error( $root ) ) {
							array_unshift( $path, $root->name );
						} else {
							break;
						}
					}
					$top     = $path[0] ?? $top;
					$paths[] = implode( ' / ', $path );
					// Aggregation Ebene 2 unter Ausgaben
					if ( ! empty( $path ) && mb_strtolower( $path[0] ) === mb_strtolower( $expense_root_name ) ) {
						$level2 = $path[1] ?? $misc_label;
						if ( ! isset( $expenseLevel2[ $level2 ] ) ) {
							$expenseLevel2[ $level2 ] = [ 'sum' => 0.0, 'count' => 0 ];
						}
						$expenseLevel2[ $level2 ]['sum'] += $amount;
						$expenseLevel2[ $level2 ]['count'] ++;
					}
				}
			}

			// Summen
			$total += $amount;
			if ( mb_strtolower( $top ) === 'einnahmen' ) {
				$income               += $amount;
				$daily[ $date ]['in'] += $amount;
			} elseif ( mb_strtolower( $top ) === 'ausgaben' ) {
				$expense               += $amount;
				$daily[ $date ]['out'] += $amount;
			}

			// Kategorie-Statistik
			foreach ( $paths as $p ) {
				if ( ! isset( $cats[ $p ] ) ) {
					$cats[ $p ] = [ 'sum' => 0.0, 'count' => 0 ];
				}
				$cats[ $p ]['sum'] += $amount;
				$cats[ $p ]['count'] ++;
			}
		}

		// Top 8 Ausgaben-Kategorien auf Ebene 2 (unterhalb Ausgaben) ermitteln
		$expenseCats = $expenseLevel2;
		uasort( $expenseCats, function ( $a, $b ) {
			return $b['sum'] <=> $a['sum'];
		} );
		$topExpenseCats = array_slice( $expenseCats, 0, 8, true );

		// Opening balance: Summe aller Buchungen vor Startdatum
		$opening_income = 0.0; $opening_expense = 0.0;
		$prev_q = new WP_Query([
			'post_type'      => 'booking',
			'post_status'    => ['publish'],
			'posts_per_page' => -1,
			'no_found_rows'  => true,
			'author'         => $user_id,
			'meta_query'     => [
				'relation' => 'AND',
				[
					'key'     => 'booking_date',
					'value'   => $start->format('Y-m-d'),
					'type'    => 'DATE',
					'compare' => '<',
				],
				[
					'key'     => 'booking_amount',
					'compare' => 'EXISTS',
				],
			],
			'fields' => 'ids',
		]);
		foreach ($prev_q->posts as $pid) {
			$amount = (float) get_post_meta($pid, 'booking_amount', true);
			$terms = wp_get_post_terms( $pid, 'booking_type' );
			$top = 'Unkategorisiert';
			if ( ! is_wp_error($terms) && ! empty($terms) ) {
				foreach ($terms as $t) {
					$root = $t;
					while ($root->parent) {
						$root = get_term($root->parent, 'booking_type');
						if (! $root || is_wp_error($root)) break;
					}
					$top = $root && !is_wp_error($root) ? $root->name : $top;
					break; // erster Term reicht zur Top-Level-Bestimmung
				}
			}
			if ( mb_strtolower( $top ) === 'einnahmen' ) {
				$opening_income += $amount;
			} elseif ( mb_strtolower( $top ) === 'ausgaben' ) {
				$opening_expense += $amount;
			}
		}
		$opening_balance = round($opening_income - $opening_expense, 2);
		$closing_balance = round($opening_balance + ($income - $expense), 2);

		$data = [
			'month'            => $ym,
			'kpi'              => [
				'total'           => round( $total, 2 ),
				'income'          => round( $income, 2 ),
				'expense'         => round( $expense, 2 ),
				'balance'         => round( $income - $expense, 2 ),
				'opening_balance' => $opening_balance,
				'closing_balance' => $closing_balance,
			],
			'cats'               => $cats,
			'top_expense_cats'   => $topExpenseCats,
			'top_expense_level'  => 2,
			'daily'              => $daily,
		];

		set_transient($cache_key, $data, 12 * HOUR_IN_SECONDS);
		return new WP_REST_Response( $data, 200 );
	}
}
