<?php
/**
 * Report Controller for Warranty Cart Admin REST API
 *
 * Handles reports and dashboard REST API operations.
 *
 * @package WarrantyCart
 */

namespace WarrantyCart\REST\Controllers;

use WarrantyCart\Core\LossRatio;

use WarrantyCart\REST\Controller;
use WarrantyCart\REST\Csv;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

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

/**
 * Reports class
 */
class Reports extends Controller {

	/**
	 * Constructor
	 */
	public function __construct() {
		$this->rest_base = 'admin';
	}

	/**
	 * Register routes
	 */
	public function register_routes(): void {
		// Reports endpoints
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/reports',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_reports' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => $this->get_reports_args(),
				),
			)
		);

		/*
		 * What the promise costs, beside what it earned.
		 *
		 * Its own route rather than more keys on `/reports`, which is built
		 * from WooCommerce orders. These figures come from the warranty and
		 * claim tables, are answered by a different set of queries, and are
		 * read by a panel that can be looked at on its own.
		 */
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/reports/loss-ratio',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_loss_ratio' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => $this->get_reports_args(),
				),
			)
		);

		// Reports export endpoint
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/reports/export',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'export_reports_csv' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array(
						'date_range' => array(
							'required'          => false,
							'type'              => 'string',
							'default'           => '30',
							'enum'              => array( '7', '30', '90', '365' ),
							'description'       => __( 'Date range in days.', 'warranty-cart' ),
							'sanitize_callback' => 'sanitize_text_field',
						),
					),
				),
			)
		);

		// Dashboard data endpoint
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/dashboard',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_dashboard' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array(
						'date_range' => array(
							'required'          => false,
							'type'              => 'integer',
							'default'           => 30,
							'description'       => __( 'Date range in days for sales data.', 'warranty-cart' ),
							'sanitize_callback' => 'absint',
							'validate_callback' => 'rest_validate_request_arg',
							'minimum'           => 1,
							'maximum'           => 365,
						),
					),
				),
			)
		);

		// Dashboard export endpoint
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/dashboard/export',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'export_dashboard_csv' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array(
						'date_range' => array(
							'required'          => false,
							'type'              => 'integer',
							'default'           => 30,
							'description'       => __( 'Date range in days for sales data.', 'warranty-cart' ),
							'sanitize_callback' => 'absint',
							'validate_callback' => 'rest_validate_request_arg',
							'minimum'           => 1,
							'maximum'           => 365,
						),
					),
				),
			)
		);
	}

	/**
	 * Get reports arguments
	 */
	private function get_reports_args(): array {
		$args = array(
			'date_range' => array(
				'required'          => false,
				'type'              => 'string',
				'default'           => '30',
				'enum'              => array( '7', '30', '90', '365' ),
				'description'       => __( 'Date range in days.', 'warranty-cart' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
		);

		/**
		 * Filter reports REST API arguments.
		 *
		 * @param array $args Arguments array.
		 */
		return apply_filters( 'warranty_cart_rest_reports_args', $args );
	}

	/**
	 * Get dashboard data
	 *
	 * Retrieves all data needed for the admin dashboard.
	 */
	public function get_dashboard( WP_REST_Request $request ): WP_REST_Response {
		$date_range = $request->get_param( 'date_range' );
		$date_range = $date_range ? absint( $date_range ) : 30;

		$dashboard_data = warranty_cart()->repository->get_dashboard_data( $date_range );

		// Add currency information
		$dashboard_data['currency']      = get_woocommerce_currency_symbol();
		$dashboard_data['currency_code'] = get_woocommerce_currency();

		return $this->success_response( $dashboard_data );
	}

	/**
	 * Get reports data
	 *
	 * Retrieves warranty sales analytics and reporting data.
	 */
	public function get_reports( WP_REST_Request $request ): WP_REST_Response {
		$date_range = (int) $request->get_param( 'date_range' );
		$reports    = warranty_cart()->repository->get_comprehensive_reports( $date_range );

		// Add currency information
		$reports['currency']      = get_woocommerce_currency_symbol();
		$reports['currency_code'] = get_woocommerce_currency();

		return $this->success_response( $reports );
	}

	/**
	 * What claims cost against what cover earned.
	 *
	 * @param WP_REST_Request $request REST request object.
	 *
	 * @return WP_REST_Response
	 */
	public function get_loss_ratio( WP_REST_Request $request ): WP_REST_Response {
		$date_range = (int) $request->get_param( 'date_range' );

		$figures = LossRatio::for_range( $date_range > 0 ? $date_range : 30 );

		$figures['currency_symbol'] = get_woocommerce_currency_symbol();

		return $this->success_response( $figures );
	}

	/**
	 * Export the reports figures as CSV.
	 *
	 * @param WP_REST_Request $request REST request object.
	 *
	 * @return WP_REST_Response
	 */
	public function export_reports_csv( WP_REST_Request $request ): WP_REST_Response {
		$date_range = (int) $request->get_param( 'date_range' );
		$data       = warranty_cart()->repository->get_comprehensive_reports( $date_range );
		$currency   = \get_woocommerce_currency();
		$loss       = LossRatio::for_range( $date_range > 0 ? $date_range : 30 );

		$rows = array(
			array( __( 'Sales', 'warranty-cart' ), __( 'Total sales', 'warranty-cart' ), $this->money( $data['total_sales'] ), $currency ),
			array( __( 'Sales', 'warranty-cart' ), __( 'Total orders', 'warranty-cart' ), $data['total_orders'], '' ),
			array( __( 'Sales', 'warranty-cart' ), __( 'Total customers', 'warranty-cart' ), $data['total_customers'], '' ),
			array( __( 'Sales', 'warranty-cart' ), __( 'Average order value', 'warranty-cart' ), $this->money( $data['average_order_value'] ), $currency ),
			array( __( 'Sales', 'warranty-cart' ), __( 'Sales growth', 'warranty-cart' ), number_format( (float) $data['sales_growth'], 2 ), '%' ),

			/*
			 * The cost half, in the same file as the revenue half.
			 *
			 * A spreadsheet holding what cover earned and not what it cost is
			 * the same flattering document the screen used to be.
			 */
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Cover sold', 'warranty-cart' ), $this->money( $loss['premium'] ), $currency ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Policies sold', 'warranty-cart' ), $loss['policies_sold'], '' ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Claims cost', 'warranty-cart' ), $this->money( $loss['claims_cost'] ), $currency ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Claims filed', 'warranty-cart' ), $loss['claims_filed'], '' ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Claims decided', 'warranty-cart' ), $loss['claims_decided'], '' ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Claims with a recorded cost', 'warranty-cart' ), $loss['claims_costed'], '' ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Loss ratio', 'warranty-cart' ), null === $loss['loss_ratio'] ? '' : $loss['loss_ratio'], '%' ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Claim rate', 'warranty-cart' ), null === $loss['claim_rate'] ? '' : $loss['claim_rate'], '%' ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Attach rate', 'warranty-cart' ), null === $loss['attach_rate'] ? '' : $loss['attach_rate'], '%' ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Cover still owed', 'warranty-cart' ), $this->money( $loss['outstanding_value'] ), $currency ),
			array( __( 'Cost of cover', 'warranty-cart' ), __( 'Policies still running', 'warranty-cart' ), $loss['outstanding_count'], '' ),

			array( __( 'Customers', 'warranty-cart' ), __( 'New', 'warranty-cart' ), $data['top_customer_segments']['new_customers'], '' ),
			array( __( 'Customers', 'warranty-cart' ), __( 'Returning', 'warranty-cart' ), $data['top_customer_segments']['returning_customers'], '' ),
			array( __( 'Customers', 'warranty-cart' ), __( 'High value', 'warranty-cart' ), $data['top_customer_segments']['high_value'], '' ),
			array( __( 'Customers', 'warranty-cart' ), __( 'Bulk purchasers', 'warranty-cart' ), $data['top_customer_segments']['bulk_purchasers'], '' ),

			array( __( 'Warranty types', 'warranty-cart' ), __( 'Main warranties', 'warranty-cart' ), $data['warranty_type_distribution']['main_warranty'], '' ),
			array( __( 'Warranty types', 'warranty-cart' ), __( 'Additional services', 'warranty-cart' ), $data['warranty_type_distribution']['additional_service'], '' ),

			array( __( 'Average term', 'warranty-cart' ), __( 'Days', 'warranty-cart' ), number_format( (float) $data['average_warranty_duration']['days'], 1 ), '' ),
			array( __( 'Average term', 'warranty-cart' ), __( 'Months', 'warranty-cart' ), number_format( (float) $data['average_warranty_duration']['months'], 1 ), '' ),
			array( __( 'Average term', 'warranty-cart' ), __( 'Years', 'warranty-cart' ), number_format( (float) $data['average_warranty_duration']['years'], 1 ), '' ),
		);

		foreach ( $data['top_products'] as $product ) {
			$rows[] = array(
				__( 'Top warranties', 'warranty-cart' ),
				$product['name'],
				$product['sales'],
				$this->money( $product['revenue'] ),
			);
		}

		foreach ( $data['monthly_data'] as $month ) {
			$rows[] = array(
				__( 'Monthly trend', 'warranty-cart' ),
				$month['month'],
				$this->money( $month['sales'] ),
				$month['orders'],
			);
		}

		return $this->file_response(
			$this->export_filename( sprintf( 'warranty-reports-%dd', $date_range ) ),
			Csv::build( $this->metric_header(), $rows )
		);
	}

	/**
	 * Export the dashboard summary as CSV.
	 *
	 * @param WP_REST_Request $request REST request object.
	 *
	 * @return WP_REST_Response
	 */
	public function export_dashboard_csv( WP_REST_Request $request ): WP_REST_Response {
		$date_range = $request->get_param( 'date_range' );
		$date_range = $date_range ? absint( $date_range ) : 30;

		$data     = warranty_cart()->repository->get_dashboard_data( $date_range );
		$currency = \get_woocommerce_currency();

		$sales       = $data['sales_overview'];
		$performance = $data['performance_metrics'];
		$status      = $data['warranty_status_summary'];

		$rows = array(
			array( __( 'Sales', 'warranty-cart' ), __( 'Total sales', 'warranty-cart' ), $this->money( $sales['total_sales'] ), $currency ),
			array( __( 'Sales', 'warranty-cart' ), __( 'Total orders', 'warranty-cart' ), $sales['total_orders'], '' ),
			array( __( 'Sales', 'warranty-cart' ), __( 'Average order', 'warranty-cart' ), $this->money( $sales['average_order'] ), $currency ),
			array( __( 'Sales', 'warranty-cart' ), __( 'Total warranties', 'warranty-cart' ), $sales['total_warranties'], '' ),
			array( __( 'Sales', 'warranty-cart' ), __( 'Active warranties', 'warranty-cart' ), $sales['active_warranties'], '' ),

			array( __( 'Performance', 'warranty-cart' ), __( 'Sales growth', 'warranty-cart' ), number_format( (float) $performance['sales_growth_percentage'], 2 ), '%' ),
			array( __( 'Performance', 'warranty-cart' ), __( 'Order growth', 'warranty-cart' ), number_format( (float) $performance['order_growth_percentage'], 2 ), '%' ),
			array( __( 'Performance', 'warranty-cart' ), __( 'This period', 'warranty-cart' ), $this->money( $performance['current_period_sales'] ), $currency ),
			array( __( 'Performance', 'warranty-cart' ), __( 'Previous period', 'warranty-cart' ), $this->money( $performance['previous_period_sales'] ), $currency ),

			array( __( 'Catalogue', 'warranty-cart' ), __( 'Total warranties', 'warranty-cart' ), $status['total_warranties'], '' ),
			array( __( 'Catalogue', 'warranty-cart' ), __( 'Active', 'warranty-cart' ), $status['active_warranties'], '' ),
			array( __( 'Catalogue', 'warranty-cart' ), __( 'Inactive', 'warranty-cart' ), $status['inactive_warranties'], '' ),
			array( __( 'Catalogue', 'warranty-cart' ), __( 'Out of stock', 'warranty-cart' ), $status['out_of_stock'], '' ),
			array( __( 'Catalogue', 'warranty-cart' ), __( 'Low stock', 'warranty-cart' ), $status['low_stock'], '' ),
		);

		foreach ( $data['popular_warranties'] as $warranty ) {
			$rows[] = array( __( 'Popular warranties', 'warranty-cart' ), $warranty['name'], $warranty['sales'], '' );
		}

		foreach ( $data['recent_orders'] as $order ) {
			$rows[] = array(
				__( 'Recent orders', 'warranty-cart' ),
				$order['customer'],
				$this->money( $order['total'] ),
				implode( '; ', $order['products'] ),
			);
		}

		foreach ( $data['monthly_sales'] as $month => $amount ) {
			$rows[] = array( __( 'Monthly sales', 'warranty-cart' ), $month, $this->money( $amount ), $currency );
		}

		foreach ( $data['alerts'] as $alert ) {
			$rows[] = array( __( 'Alerts', 'warranty-cart' ), ucfirst( (string) $alert['type'] ), $alert['message'], '' );
		}

		return $this->file_response(
			$this->export_filename( sprintf( 'warranty-dashboard-%dd', $date_range ) ),
			Csv::build( $this->metric_header(), $rows )
		);
	}

	/**
	 * Column titles shared by both metric exports.
	 *
	 * @return array<int, string>
	 */
	private function metric_header(): array {
		return array(
			__( 'Section', 'warranty-cart' ),
			__( 'Metric', 'warranty-cart' ),
			__( 'Value', 'warranty-cart' ),
			__( 'Detail', 'warranty-cart' ),
		);
	}

	/**
	 * A figure a spreadsheet can add up.
	 *
	 * Both exports ran every amount through `wc_price()`, which returns markup —
	 * `<span class="woocommerce-Price-amount">&#36;42.00</span>` — so the value
	 * columns held HTML and none of them could be summed, charted or sorted. The
	 * currency belongs in its own column, which is what the Detail column is for
	 * on the money rows.
	 *
	 * @param mixed $amount The amount.
	 *
	 * @return string
	 */
	private function money( $amount ): string {
		return \wc_format_decimal( (float) $amount, \wc_get_price_decimals() );
	}
}
