<?php
/**
 * Order Controller for Warranty Cart Admin REST API
 *
 * Handles order-related REST API operations.
 *
 * @package WarrantyCart
 */

namespace WarrantyCart\REST\Controllers;

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

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

/**
 * Orders class
 */
class Orders extends Controller {

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

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

		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/orders/(?P<id>\d+)',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'get_order' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array(
						'id' => array(
							'required'          => true,
							'type'              => 'integer',
							'description'       => __( 'Order ID.', 'warranty-cart' ),
							'sanitize_callback' => 'absint',
						),
					),
				),
			)
		);

		// Order PDF download endpoint
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/orders/(?P<id>\d+)/pdf',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'download_order_pdf' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array(
						'id' => array(
							'required'          => true,
							'type'              => 'integer',
							'description'       => __( 'Order ID.', 'warranty-cart' ),
							'sanitize_callback' => 'absint',
						),
					),
				),
			)
		);

		// Order status update endpoint
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/orders/(?P<id>\d+)/status',
			array(
				array(
					'methods'             => WP_REST_Server::EDITABLE,
					'callback'            => array( $this, 'update_order_status' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array(
						'id'     => array(
							'required'          => true,
							'type'              => 'integer',
							'description'       => __( 'Order ID.', 'warranty-cart' ),
							'sanitize_callback' => 'absint',
						),
						'status' => array(
							'required'          => true,
							'type'              => 'string',
							'enum'              => array( 'pending', 'processing', 'completed', 'cancelled', 'refunded' ),
							'description'       => __( 'New order status.', 'warranty-cart' ),
							'sanitize_callback' => 'sanitize_text_field',
						),
					),
				),
			)
		);

		// Orders CSV export endpoint
		register_rest_route(
			$this->namespace,
			'/' . $this->rest_base . '/orders/export',
			array(
				array(
					'methods'             => WP_REST_Server::READABLE,
					'callback'            => array( $this, 'export_orders_csv' ),
					'permission_callback' => array( $this, 'check_admin_permission' ),
					'args'                => array_merge(
						$this->get_orders_args(),
						array(
							'format' => array(
								'required'          => false,
								'type'              => 'string',
								'default'           => 'csv',
								'enum'              => array( 'csv' ),
								'description'       => __( 'Export format.', 'warranty-cart' ),
								'sanitize_callback' => 'sanitize_text_field',
							),
						)
					),
				),
			)
		);
	}

	/**
	 * Get orders endpoint arguments.
	 *
	 * @return array
	 */
	private function get_orders_args(): array {
		$args = array(
			'page'     => array(
				'required'    => false,
				'type'        => 'integer',
				'default'     => 1,
				'description' => __( 'Page number.', 'warranty-cart' ),
				'minimum'     => 1,
			),
			'per_page' => array(
				'required'    => false,
				'type'        => 'integer',
				'default'     => 10,
				'description' => __( 'Items per page.', 'warranty-cart' ),
				'minimum'     => 1,
				'maximum'     => 100,
			),
			'search'   => array(
				'required'          => false,
				'type'              => 'string',
				'description'       => __( 'Search term.', 'warranty-cart' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
			'status'   => array(
				'required'          => false,
				'type'              => 'string',
				'enum'              => array( 'completed', 'pending', 'cancelled' ),
				'description'       => __( 'Order status filter.', 'warranty-cart' ),
				'sanitize_callback' => 'sanitize_text_field',
			),
		);

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

	/**
	 * Get warranty orders with pagination and filtering.
	 *
	 * @param WP_REST_Request $request REST request object.
	 *
	 * @return WP_REST_Response
	 */
	public function get_orders( WP_REST_Request $request ): WP_REST_Response {
		$page     = $request->get_param( 'page' );
		$per_page = $request->get_param( 'per_page' );
		$search   = $request->get_param( 'search' );
		$status   = $request->get_param( 'status' );

		/**
		 * Filter orders query arguments
		 *
		 * @param array           $query_args Query arguments.
		 * @param WP_REST_Request $request    Request object.
		 */
		$query_args = apply_filters(
			'warranty_cart_rest_orders_query_args',
			array(
				'limit'   => $per_page,
				'page'    => $page,
				'orderby' => 'date',
				'order'   => 'DESC',
			),
			$request
		);

		// Add status filter if provided
		if ( $status ) {
			$query_args['status'] = $status;
		}

		// Add search if provided
		if ( $search ) {
			$query_args['s'] = $search;
		}

		// Get formatted orders data from Reports class
		$response_data = warranty_cart()->repository->get_formatted_warranty_orders( $query_args, true );

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

		/**
		 * Filter orders REST response data
		 *
		 * @param array           $response_data Response data.
		 * @param WP_REST_Request $request       Request object.
		 */
		$response_data = apply_filters( 'warranty_cart_rest_orders_response', $response_data, $request );

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

	/**
	 * Get single order
	 *
	 * Retrieves detailed information for a specific warranty order.
	 */
	public function get_order( WP_REST_Request $request ) {
		$order_id = $request->get_param( 'id' );

		$order_data = warranty_cart()->repository->get_single_warranty_order( $order_id );

		if ( null === $order_data ) {
			return $this->error_response( __( 'Order not found or does not contain warranty products.', 'warranty-cart' ), 404 );
		}

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

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

	/**
	 * Download order PDF
	 *
	 * Generates and downloads a PDF warranty certificate for a specific order.
	 */
	public function download_order_pdf( WP_REST_Request $request ) {
		$order_id = $request->get_param( 'id' );

		$order = wc_get_order( $order_id );
		if ( ! $order instanceof WC_Order ) {
			return $this->error_response( __( 'Order not found.', 'warranty-cart' ), 404 );
		}

		// Check if order contains warranty products
		$warranty_data = warranty_cart()->repository->get_order_warranty_items( $order );
		if ( 0 === $warranty_data['count'] ) {
			return $this->error_response( __( 'Order does not contain warranty products.', 'warranty-cart' ), 404 );
		}

		// Generate PDF using the existing email functionality
		$email_class = new \WarrantyCart\Notifications\Emails\OrderCompletion();

		// Initialize the email class with the order (this sets $this->order)
		$email_class->trigger( $order_id );

		// Generate the PDF
		$pdf_path = $email_class->generate_warranty_pdf();

		if ( ! $pdf_path || ! file_exists( $pdf_path ) ) {
			return $this->error_response( __( 'Failed to generate PDF certificate.', 'warranty-cart' ), 500 );
		}

		// Set headers for file download
		header( 'Content-Type: application/pdf' );
		header( 'Content-Disposition: attachment; filename="' . basename( $pdf_path ) . '"' );
		header( 'Content-Length: ' . filesize( $pdf_path ) );
		header( 'Cache-Control: private, max-age=0, must-revalidate' );
		header( 'Pragma: public' );

		// Output the file using unified filesystem method
		$pdf_contents = warranty_cart()->read_file( $pdf_path );
		if ( false !== $pdf_contents ) {
			// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
			echo $pdf_contents;
		}

		// Clean up the temporary file
		wp_delete_file( $pdf_path );

		// Exit to prevent any further output
		exit;
	}

	/**
	 * Update order status
	 *
	 * Updates the status of a warranty order.
	 */
	public function update_order_status( WP_REST_Request $request ) {
		$order_id = $request->get_param( 'id' );
		$status   = $request->get_param( 'status' );

		$order = wc_get_order( $order_id );
		if ( ! $order instanceof WC_Order ) {
			return $this->error_response( __( 'Order not found.', 'warranty-cart' ), 404 );
		}

		// Check if order contains warranty products
		$warranty_data = warranty_cart()->repository->get_order_warranty_items( $order );
		if ( 0 === $warranty_data['count'] ) {
			return $this->error_response( __( 'Order does not contain warranty products.', 'warranty-cart' ), 404 );
		}

		// Update order status
		$order->set_status( $status );
		$order->save();

		return $this->success_response(
			array(
				'message' => __( 'Order status updated successfully.', 'warranty-cart' ),
				'status'  => $status,
			)
		);
	}

	/**
	 * Export warranty orders as CSV.
	 *
	 * @param WP_REST_Request $request REST request object.
	 *
	 * @return WP_REST_Response|WP_Error
	 */
	public function export_orders_csv( WP_REST_Request $request ) {
		$search = $request->get_param( 'search' );
		$status = $request->get_param( 'status' );

		$query_args = array(
			'limit'   => -1,
			'orderby' => 'date',
			'order'   => 'DESC',
		);

		if ( $status ) {
			$query_args['status'] = $status;
		}

		if ( $search ) {
			$query_args['s'] = $search;
		}

		/*
		 * `false` returns the orders themselves, as a flat array.
		 *
		 * This read `$response_data['orders']` off that flat array, so the key
		 * was always missing, the emptiness check always passed, and the button
		 * answered 404 "No orders found to export" on a shop with orders. The
		 * export had never worked.
		 */
		$orders = warranty_cart()->repository->get_formatted_warranty_orders( $query_args, false );

		if ( empty( $orders ) ) {
			return $this->error_response( __( 'No orders found to export.', 'warranty-cart' ), 404 );
		}

		return $this->file_response(
			$this->export_filename( 'warranty-orders' ),
			$this->generate_orders_csv( $orders )
		);
	}

	/**
	 * Build the orders CSV.
	 *
	 * @param array<int, WC_Order> $orders Orders to write.
	 *
	 * @return string CSV content.
	 */
	private function generate_orders_csv( array $orders ): string {
		$header = array(
			__( 'Order ID', 'warranty-cart' ),
			__( 'Order Date', 'warranty-cart' ),
			__( 'Status', 'warranty-cart' ),
			__( 'Customer Name', 'warranty-cart' ),
			__( 'Customer Email', 'warranty-cart' ),
			__( 'Billing Phone', 'warranty-cart' ),
			__( 'Billing Address', 'warranty-cart' ),
			__( 'Billing City', 'warranty-cart' ),
			__( 'Billing Postcode', 'warranty-cart' ),
			__( 'Billing Country', 'warranty-cart' ),
			__( 'Warranty Items', 'warranty-cart' ),
			__( 'Warranty Total', 'warranty-cart' ),
			__( 'Order Subtotal', 'warranty-cart' ),
			__( 'Order Tax', 'warranty-cart' ),
			__( 'Order Total', 'warranty-cart' ),
			__( 'Currency', 'warranty-cart' ),
			__( 'Payment Method', 'warranty-cart' ),
			__( 'Customer Note', 'warranty-cart' ),
		);

		$rows = array();

		foreach ( $orders as $order ) {
			if ( ! $order instanceof WC_Order ) {
				continue;
			}

			/*
			 * Ask the repository what the warranty lines are.
			 *
			 * This tested `has_term( 'warranties', 'product_cat' )` — a category
			 * the plugin never creates and never assigns. Nothing ever matched,
			 * so the column this export exists for was blank on every row.
			 */
			$warranty_data  = warranty_cart()->repository->get_order_warranty_items( $order );
			$warranty_items = array();
			$warranty_total = 0.0;

			foreach ( $warranty_data['items'] as $item ) {
				$warranty_items[] = sprintf( '%s (x%d)', $item['product_name'], $item['quantity'] );
				$warranty_total  += (float) $item['total'];
			}

			$created = $order->get_date_created();

			$rows[] = array(
				$order->get_order_number(),
				$created ? $created->date( 'Y-m-d H:i:s' ) : '',
				\wc_get_order_status_name( $order->get_status() ),
				trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() ),
				$order->get_billing_email(),
				$order->get_billing_phone(),
				trim( $order->get_billing_address_1() . ' ' . $order->get_billing_address_2() ),
				$order->get_billing_city(),
				$order->get_billing_postcode(),
				$order->get_billing_country(),
				implode( '; ', $warranty_items ),

				/*
				 * Raw decimals, not wc_price().
				 *
				 * Every figure here went through wc_price(), which returns a
				 * span of HTML with the currency symbol as an entity — so a
				 * column of totals arrived in the spreadsheet as markup that
				 * could not be summed. The currency has a column of its own.
				 */
				\wc_format_decimal( $warranty_total, \wc_get_price_decimals() ),
				\wc_format_decimal( $order->get_subtotal(), \wc_get_price_decimals() ),
				\wc_format_decimal( $order->get_total_tax(), \wc_get_price_decimals() ),
				\wc_format_decimal( $order->get_total(), \wc_get_price_decimals() ),
				$order->get_currency(),
				$order->get_payment_method_title(),
				$order->get_customer_note(),
			);
		}

		return Csv::build( $header, $rows );
	}
}
