<?php

namespace Antimanual\Api;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Antimanual\UsageTracker;

/**
 * Usage & Cost analytics and per-role spend-limit endpoints.
 *
 * Reports AI requests, token usage, and estimated cost over time, and manages
 * the per-role monthly token caps enforced across the plugin's AI features.
 */
class UsageAnalyticsController {

	/**
	 * Register REST routes.
	 *
	 * @param string $namespace REST namespace.
	 */
	public function register_routes( string $namespace ) {
		register_rest_route(
			$namespace,
			'/usage-analytics',
			[
				'methods'             => 'GET',
				'callback'            => [ $this, 'get_analytics' ],
				'permission_callback' => fn() => current_user_can( 'manage_options' ),
				'args'                => [
					'days' => [
						'sanitize_callback' => 'absint',
						'default'           => 30,
					],
				],
			]
		);

		register_rest_route(
			$namespace,
			'/usage-analytics/export-csv',
			[
				'methods'             => 'GET',
				'callback'            => [ $this, 'export_csv' ],
				'permission_callback' => fn() => current_user_can( 'manage_options' ),
				'args'                => [
					'days' => [
						'sanitize_callback' => 'absint',
						'default'           => 30,
					],
				],
			]
		);

		register_rest_route(
			$namespace,
			'/usage-limits',
			[
				[
					'methods'             => 'GET',
					'callback'            => [ $this, 'get_limits' ],
					'permission_callback' => fn() => current_user_can( 'manage_options' ),
				],
				[
					'methods'             => 'POST',
					'callback'            => [ $this, 'save_limits' ],
					'permission_callback' => fn() => current_user_can( 'manage_options' ),
				],
			]
		);
	}

	/**
	 * Return aggregated usage analytics for the requested window.
	 *
	 * @param \WP_REST_Request $request REST request.
	 * @return \WP_REST_Response
	 */
	public function get_analytics( $request ) {
		$days = (int) $request->get_param( 'days' );
		$days = $days > 0 ? min( 365, $days ) : 30;

		$summary  = UsageTracker::get_summary( $days );
		$previous = UsageTracker::get_previous_summary( $days );

		return rest_ensure_response(
			[
				'success' => true,
				'data'    => [
					'days'         => $days,
					'currency'     => 'USD',
					'has_data'     => UsageTracker::has_cost_columns(),
					'summary'      => $summary,
					'previous'     => $previous,
					'trend'        => [
						'requests'     => $this->delta( $summary['requests'], $previous['requests'] ),
						'total_tokens' => $this->delta( $summary['total_tokens'], $previous['total_tokens'] ),
						'cost'         => $this->delta( $summary['cost'], $previous['cost'] ),
					],
					'avg_cost_per_request' => $summary['requests'] > 0 ? round( $summary['cost'] / $summary['requests'], 5 ) : 0,
					'by_feature'   => UsageTracker::get_by_feature( $days ),
					'by_provider'  => UsageTracker::get_by_provider( $days ),
					'by_model'     => UsageTracker::get_by_model( $days ),
					'by_user'      => UsageTracker::get_by_user( $days ),
					'daily'        => UsageTracker::get_daily_series( $days ),
					'user_status'  => atml_usage_limit_status(),
				],
			]
		);
	}

	/**
	 * Compute a percentage change and direction between two values.
	 *
	 * @param float $current  Current-period value.
	 * @param float $previous Previous-period value.
	 * @return array{percent:float,direction:string}
	 */
	private function delta( $current, $previous ): array {
		$current  = (float) $current;
		$previous = (float) $previous;

		if ( $previous <= 0 ) {
			$percent = $current > 0 ? 100.0 : 0.0;
		} else {
			$percent = ( ( $current - $previous ) / $previous ) * 100;
		}

		$direction = 'neutral';
		if ( $current > $previous ) {
			$direction = 'up';
		} elseif ( $current < $previous ) {
			$direction = 'down';
		}

		return [
			'percent'   => round( abs( $percent ), 1 ),
			'direction' => $direction,
		];
	}

	/**
	 * Export the daily usage series and per-feature breakdown as CSV text.
	 *
	 * @param \WP_REST_Request $request REST request.
	 * @return \WP_REST_Response
	 */
	public function export_csv( $request ) {
		$days = (int) $request->get_param( 'days' );
		$days = $days > 0 ? min( 365, $days ) : 30;

		$lines   = [];
		$lines[] = 'Section,Name,Requests,Tokens,Cost (USD)';

		foreach ( UsageTracker::get_daily_series( $days ) as $point ) {
			$lines[] = sprintf( 'Daily,%s,%d,%d,%.6f', $point['date'], $point['requests'], $point['total_tokens'], $point['cost'] );
		}

		foreach ( UsageTracker::get_by_feature( $days ) as $row ) {
			$lines[] = sprintf( 'Feature,"%s",%d,%d,%.6f', str_replace( '"', '""', $row['feature'] ), $row['requests'], $row['total_tokens'], $row['cost'] );
		}

		foreach ( UsageTracker::get_by_provider( $days ) as $row ) {
			$lines[] = sprintf( 'Provider,"%s",%d,%d,%.6f', str_replace( '"', '""', $row['provider'] ), $row['requests'], $row['total_tokens'], $row['cost'] );
		}

		foreach ( UsageTracker::get_by_model( $days ) as $row ) {
			$lines[] = sprintf( 'Model,"%s",%d,%d,%.6f', str_replace( '"', '""', $row['model'] ), $row['requests'], $row['total_tokens'], $row['cost'] );
		}

		foreach ( UsageTracker::get_by_user( $days ) as $row ) {
			$lines[] = sprintf( 'User,"%s",%d,%d,%.6f', str_replace( '"', '""', $row['user'] ), $row['requests'], $row['total_tokens'], $row['cost'] );
		}

		return rest_ensure_response(
			[
				'success' => true,
				'data'    => [
					'csv'      => implode( "\n", $lines ),
					'filename' => 'antimanual-usage-' . gmdate( 'Y-m-d' ) . '.csv',
				],
			]
		);
	}

	/**
	 * Return the per-role limit configuration plus the list of assignable roles.
	 *
	 * @return \WP_REST_Response
	 */
	public function get_limits() {
		return rest_ensure_response(
			[
				'success' => true,
				'data'    => [
					'config' => atml_get_usage_limits(),
					'roles'  => $this->get_editable_roles(),
				],
			]
		);
	}

	/**
	 * Persist the per-role limit configuration.
	 *
	 * @param \WP_REST_Request $request REST request.
	 * @return \WP_REST_Response
	 */
	public function save_limits( $request ) {
		$payload = json_decode( $request->get_body(), true );

		if ( ! is_array( $payload ) ) {
			return rest_ensure_response(
				[
					'success' => false,
					'message' => __( 'Invalid usage-limit payload.', 'antimanual' ),
				]
			);
		}

		$valid_roles = array_keys( $this->get_editable_roles() );

		$roles = [];
		if ( isset( $payload['roles'] ) && is_array( $payload['roles'] ) ) {
			foreach ( $payload['roles'] as $role => $cap ) {
				$role = sanitize_key( (string) $role );
				if ( in_array( $role, $valid_roles, true ) ) {
					$roles[ $role ] = max( 0, absint( $cap ) );
				}
			}
		}

		$config = [
			'enabled'       => ! empty( $payload['enabled'] ),
			'exempt_admins' => ! empty( $payload['exempt_admins'] ),
			'roles'         => $roles,
		];

		update_option( ATML_USAGE_LIMITS_OPTION, $config );

		return rest_ensure_response(
			[
				'success' => true,
				'data'    => [
					'message' => __( 'Usage limits saved.', 'antimanual' ),
					'config'  => atml_get_usage_limits(),
				],
			]
		);
	}

	/**
	 * Build a slug => display-name map of assignable roles, excluding the
	 * administrator role (admins are governed by the exempt-admins toggle).
	 *
	 * @return array<string, string>
	 */
	private function get_editable_roles(): array {
		if ( ! function_exists( 'get_editable_roles' ) ) {
			require_once ABSPATH . 'wp-admin/includes/user.php';
		}

		$roles = [];
		foreach ( get_editable_roles() as $slug => $details ) {
			if ( 'administrator' === $slug ) {
				continue;
			}
			$roles[ $slug ] = translate_user_role( $details['name'] ?? $slug );
		}

		return $roles;
	}
}
