<?php

declare( strict_types=1 );

namespace Brightfern\Inbound;

/**
 * Admin "Inbox" for received e-invoices: a list view with parsed summaries,
 * order-match status, a detail view (parsed fields + raw XML download), and a
 * manual match action for anything the matcher couldn't resolve.
 *
 * Registered as a WooCommerce submenu so it sits where merchants expect it.
 */
final class InboundInbox {

	public const PAGE = 'brightfern-inbox';

	public function register(): void {
		add_action( 'admin_menu', array( $this, 'addMenu' ) );
		add_action( 'admin_post_brightfern_inbound_download', array( $this, 'downloadXml' ) );
		add_action( 'admin_post_brightfern_inbound_match', array( $this, 'saveMatch' ) );
	}

	public function addMenu(): void {
		$counts = InboundStore::countsByStatus();
		$unread = (int) ( $counts[ InboundStore::STATUS_UNMATCHED ] ?? 0 );
		$title  = __( 'E-Invoice Inbox', 'brightfern-e-invoicing-for-woocommerce' );
		if ( $unread > 0 ) {
			$title .= ' <span class="awaiting-mod">' . esc_html( (string) $unread ) . '</span>';
		}

		add_submenu_page(
			'woocommerce',
			__( 'E-Invoice Inbox', 'brightfern-e-invoicing-for-woocommerce' ),
			$title,
			'manage_woocommerce',
			self::PAGE,
			array( $this, 'render' )
		);
	}

	public function render(): void {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		$detailId = isset( $_GET['inbound'] ) ? absint( wp_unslash( $_GET['inbound'] ) ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( $detailId > 0 ) {
			$this->renderDetail( $detailId );
			return;
		}

		$rows = InboundStore::query( array( 'limit' => 100 ) );

		echo '<div class="wrap"><h1>' . esc_html__( 'E-Invoice Inbox', 'brightfern-e-invoicing-for-woocommerce' ) . '</h1>';
		echo '<p>' . esc_html__( 'E-invoices received over the network. Brightfern tries to match each to an order; unmatched ones can be matched manually.', 'brightfern-e-invoicing-for-woocommerce' ) . '</p>';

		echo '<table class="wp-list-table widefat fixed striped"><thead><tr>';
		$columns = array(
			__( 'Received', 'brightfern-e-invoicing-for-woocommerce' ),
			__( 'Supplier', 'brightfern-e-invoicing-for-woocommerce' ),
			__( 'Invoice #', 'brightfern-e-invoicing-for-woocommerce' ),
			__( 'Amount', 'brightfern-e-invoicing-for-woocommerce' ),
			__( 'Status', 'brightfern-e-invoicing-for-woocommerce' ),
			__( 'Order', 'brightfern-e-invoicing-for-woocommerce' ),
			'',
		);
		foreach ( $columns as $col ) {
			echo '<th>' . esc_html( $col ) . '</th>';
		}
		echo '</tr></thead><tbody>';

		if ( empty( $rows ) ) {
			echo '<tr><td colspan="7">' . esc_html__( 'No e-invoices received yet.', 'brightfern-e-invoicing-for-woocommerce' ) . '</td></tr>';
		}

		foreach ( $rows as $row ) {
			$view = add_query_arg(
				array( 'page' => self::PAGE, 'inbound' => (int) $row['id'] ),
				admin_url( 'admin.php' )
			);
			$order = (int) $row['matched_order_id'];
			echo '<tr>';
			echo '<td>' . esc_html( (string) $row['received_at'] ) . '</td>';
			echo '<td>' . esc_html( (string) $row['supplier_name'] ) . '<br><small>' . esc_html( (string) $row['supplier_vat'] ) . '</small></td>';
			echo '<td>' . esc_html( (string) $row['invoice_number'] ) . '</td>';
			echo '<td>' . esc_html( number_format_i18n( (float) $row['payable_amount'], 2 ) . ' ' . (string) $row['currency'] ) . '</td>';
			echo '<td>' . esc_html( (string) $row['status'] ) . '</td>';
			// wc_get_order()->get_edit_order_url(), NOT get_edit_post_link(): the
			// latter is a post-table API applied to an order id, and under HPOS
			// (this plugin declares custom_order_tables compatibility) an order is
			// at best a legacy placeholder post there — get_edit_post_link() only
			// works via WooCommerce's own legacy-URL redirect shim, and can return
			// null for a deleted/placeholder order, which used to silently send the
			// merchant to the plain dashboard instead of erroring or omitting the link.
			$matchedOrder = $order > 0 ? wc_get_order( $order ) : false;
			$editUrl      = $matchedOrder ? $matchedOrder->get_edit_order_url() : '';
			echo '<td>' . ( '' !== $editUrl ? '<a href="' . esc_url( $editUrl ) . '">#' . esc_html( (string) $order ) . '</a>' : ( $order > 0 ? '#' . esc_html( (string) $order ) : '&mdash;' ) ) . '</td>';
			echo '<td><a href="' . esc_url( $view ) . '">' . esc_html__( 'View', 'brightfern-e-invoicing-for-woocommerce' ) . '</a></td>';
			echo '</tr>';
		}

		echo '</tbody></table></div>';
	}

	private function renderDetail( int $id ): void {
		$row = InboundStore::get( $id );
		if ( null === $row ) {
			echo '<div class="wrap"><p>' . esc_html__( 'Document not found.', 'brightfern-e-invoicing-for-woocommerce' ) . '</p></div>';
			return;
		}

		$summary  = json_decode( (string) $row['summary'], true );
		$summary  = is_array( $summary ) ? $summary : array();
		$back     = add_query_arg( array( 'page' => self::PAGE ), admin_url( 'admin.php' ) );
		$download = wp_nonce_url(
			admin_url( 'admin-post.php?action=brightfern_inbound_download&id=' . $id ),
			'brightfern_inbound_download_' . $id
		);

		echo '<div class="wrap"><h1>' . esc_html__( 'Received E-Invoice', 'brightfern-e-invoicing-for-woocommerce' ) . '</h1>';
		echo '<p><a href="' . esc_url( $back ) . '">&larr; ' . esc_html__( 'Back to inbox', 'brightfern-e-invoicing-for-woocommerce' ) . '</a></p>';

		echo '<table class="form-table"><tbody>';
		foreach ( $summary as $key => $value ) {
			echo '<tr><th>' . esc_html( (string) $key ) . '</th><td>' . esc_html( is_scalar( $value ) ? (string) $value : wp_json_encode( $value ) ) . '</td></tr>';
		}
		echo '<tr><th>' . esc_html__( 'Sender', 'brightfern-e-invoicing-for-woocommerce' ) . '</th><td>' . esc_html( (string) $row['sender_id'] ) . '</td></tr>';
		echo '</tbody></table>';

		echo '<p><a class="button" href="' . esc_url( $download ) . '">' . esc_html__( 'Download XML', 'brightfern-e-invoicing-for-woocommerce' ) . '</a></p>';

		// Manual match form.
		echo '<h2>' . esc_html__( 'Match to order', 'brightfern-e-invoicing-for-woocommerce' ) . '</h2>';
		echo '<form method="post" action="' . esc_url( admin_url( 'admin-post.php' ) ) . '">';
		echo '<input type="hidden" name="action" value="brightfern_inbound_match" />';
		echo '<input type="hidden" name="id" value="' . esc_attr( (string) $id ) . '" />';
		wp_nonce_field( 'brightfern_inbound_match_' . $id );
		echo '<input type="number" name="order_id" value="' . esc_attr( (string) (int) $row['matched_order_id'] ) . '" min="0" /> ';
		echo '<button type="submit" class="button button-primary">' . esc_html__( 'Save match', 'brightfern-e-invoicing-for-woocommerce' ) . '</button>';
		echo '</form></div>';
	}

	public function saveMatch(): void {
		$id = isset( $_POST['id'] ) ? absint( wp_unslash( $_POST['id'] ) ) : 0;
		check_admin_referer( 'brightfern_inbound_match_' . $id );
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'brightfern-e-invoicing-for-woocommerce' ) );
		}
		$orderId = isset( $_POST['order_id'] ) ? absint( wp_unslash( $_POST['order_id'] ) ) : 0;
		// A manual match is a deliberate admin action, not sender-controlled
		// input — this isn't a trust boundary the way OrderMatcher's automatic
		// matching is. The check here is purely against a typo: confirm the
		// typed id actually resolves before storing it, rather than silently
		// keeping a dangling reference to an order that doesn't exist.
		if ( $orderId > 0 && ! wc_get_order( $orderId ) ) {
			$orderId = 0;
		}
		InboundStore::setMatch( $id, $orderId );

		wp_safe_redirect( add_query_arg( array( 'page' => self::PAGE, 'inbound' => $id ), admin_url( 'admin.php' ) ) );
		exit;
	}

	public function downloadXml(): void {
		$id = isset( $_GET['id'] ) ? absint( wp_unslash( $_GET['id'] ) ) : 0;
		check_admin_referer( 'brightfern_inbound_download_' . $id );
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'brightfern-e-invoicing-for-woocommerce' ) );
		}
		$row = InboundStore::get( $id );
		if ( null === $row ) {
			wp_die( esc_html__( 'Document not found.', 'brightfern-e-invoicing-for-woocommerce' ) );
		}

		$filename = 'inbound-' . ( '' !== $row['invoice_number'] ? sanitize_file_name( (string) $row['invoice_number'] ) : (string) $id ) . '.xml';
		header( 'Content-Type: application/xml; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
		// Raw XML file download: escaping would corrupt the document, and the
		// Content-Type/Disposition headers above mean it is never rendered as HTML.
		echo (string) $row['xml']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- XML file download, must not be escaped.
		exit;
	}
}
