<?php
/**
 * Metabox na ekranie zamówienia WC: wystawienie faktury KSeF + jej status.
 *
 * Przed wystawieniem: typ klienta / polityka + przycisk „Wystaw fakturę".
 * Po wystawieniu: numer, data, kwota, status KSeF + UPO/błąd + podgląd faktury.
 * Obsługuje legacy edit screen (posts) oraz HPOS.
 *
 * @package KSEF\WordPress\WC
 */

declare(strict_types=1);

namespace KSEF\WordPress\WC;

// phpcs:disable WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders, WordPress.DB.SlowDBQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Wlasne tabele gksef_*: wartosci przez $wpdb->prepare()/esc_like(), nazwy tabel z $wpdb->prefix, paginacja rzutowana (int); nonce weryfikowany w handlerze (check_ajax_referer/check_admin_referer).

final class Order_Metabox {

	private const NONCE_ACTION = 'ksef_manual_send';
	private const NONCE_NAME   = 'ksef_manual_send_nonce';

	public static function register(): void {
		add_action( 'add_meta_boxes', [ self::class, 'add_metabox' ] );
		add_action( 'admin_post_ksef_send_invoice_now', [ self::class, 'handle_manual_send' ] );
		add_action( 'admin_post_ksef_check_invoice_status', [ self::class, 'handle_check_status' ] );
	}

	public static function add_metabox(): void {
		$screens = [ 'shop_order' ];
		if ( class_exists( '\Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController' ) ) {
			$screens[] = wc_get_page_screen_id( 'shop-order' );
		}
		foreach ( $screens as $screen ) {
			add_meta_box(
				'ksef_invoice_box',
				__( 'KSeF — faktura', 'prostafaktura-ksef' ),
				[ self::class, 'render_metabox' ],
				$screen,
				'side',
				'high'
			);
		}
	}

	/** @return array<string,mixed>|null */
	private static function find_invoice( int $order_id ): ?array {
		global $wpdb;
		$row = $wpdb->get_row( $wpdb->prepare(
			"SELECT id, invoice_number, status, gross_amount, ksef_reference_number, created_at,
			        LENGTH( COALESCE( upo_xml, '' ) ) AS upo_len, offline_reason
			   FROM {$wpdb->prefix}gksef_outgoing_invoices
			  WHERE wc_order_id = %d ORDER BY id DESC LIMIT 1",
			$order_id
		), ARRAY_A );
		return $row ?: null;
	}

	public static function render_metabox( $post_or_order ): void {
		$order = $post_or_order instanceof \WC_Order
			? $post_or_order
			: wc_get_order( is_object( $post_or_order ) ? $post_or_order->ID : (int) $post_or_order );
		if ( ! $order ) {
			echo '<em>' . esc_html__( 'Nie udało się pobrać zamówienia.', 'prostafaktura-ksef' ) . '</em>';
			return;
		}

		$inv = self::find_invoice( $order->get_id() );

		if ( $inv ) {
			self::render_issued( $order, $inv );
			return;
		}
		// Brak rekordu faktury, ale meta zamówienia może wskazywać próbę wysyłki bez utworzonego
		// rekordu (np. błąd uwierzytelniania PRZED zapisem → status=failed). Pokaż właściwy stan,
		// zamiast mylącego „przed wystawieniem".
		$ostatus = (string) $order->get_meta( '_ksef_invoice_status' );
		if ( in_array( $ostatus, [ 'failed', 'queued', 'sent', 'pending', 'confirmed', 'rejected', 'issued' ], true ) ) {
			self::render_order_status_state( $order, $ostatus );
			return;
		}
		self::render_not_issued( $order );
	}

	/**
	 * Stan oparty WYŁĄCZNIE o meta zamówienia (brak rekordu w gksef_outgoing_invoices) —
	 * np. nieudana wysyłka, gdzie błąd wystąpił przed zapisem faktury.
	 */
	private static function render_order_status_state( \WC_Order $order, string $status ): void {
		$number = (string) $order->get_meta( '_ksef_invoice_number' );
		if ( '' !== $number ) {
			echo '<p style="margin:.2em 0"><strong>' . esc_html__( 'Numer:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( $number ) . '</p>';
		}

		if ( 'failed' === $status ) {
			self::badge( '#c0392b', __( '✗ Wysyłka do KSeF nie powiodła się', 'prostafaktura-ksef' ) );
			$err = (string) $order->get_meta( '_ksef_invoice_error' );
			if ( '' !== $err ) {
				echo '<p style="margin:.5em 0;color:#c0392b"><small><strong>' . esc_html__( 'Błąd:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( $err ) . '</small></p>';
			}
			echo '<p style="margin:.3em 0;color:#777"><small>' . esc_html__( 'Faktura NIE została wystawiona w KSeF.', 'prostafaktura-ksef' );
			if ( '' !== $number ) {
				// translators: %s = numer faktury
				echo ' ' . sprintf( esc_html__( 'Numer %s jest zarezerwowany — „Ponów wysyłkę" użyje go ponownie (bez dziury w numeracji).', 'prostafaktura-ksef' ), '<code>' . esc_html( $number ) . '</code>' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- numer zescapowany przez esc_html powyzej.
			}
			echo '</small></p>';
			echo self::action_button( 'ksef_send_invoice_now', (int) $order->get_id(), __( 'Ponów wysyłkę', 'prostafaktura-ksef' ), true, __( 'Trwa wystawianie…', 'prostafaktura-ksef' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wyjscie zbudowane/escapowane przy zrodle.
			return;
		}

		if ( 'rejected' === $status ) {
			self::badge( '#c0392b', __( '✗ Odrzucona przez KSeF', 'prostafaktura-ksef' ) );
			$err = (string) $order->get_meta( '_ksef_invoice_error' );
			if ( '' !== $err ) {
				echo '<p style="margin:.5em 0;color:#c0392b"><small><strong>' . esc_html__( 'Powód:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( $err ) . '</small></p>';
			}
			echo self::action_button( 'ksef_send_invoice_now', (int) $order->get_id(), __( 'Wystaw ponownie', 'prostafaktura-ksef' ), true, __( 'Trwa wystawianie…', 'prostafaktura-ksef' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wyjscie zbudowane/escapowane przy zrodle.
			return;
		}

		if ( 'confirmed' === $status ) {
			self::badge( '#22863a', __( '✓ Przyjęta przez KSeF', 'prostafaktura-ksef' ) );
			$ref = (string) $order->get_meta( '_ksef_reference_number' );
			if ( '' !== $ref ) {
				echo '<p style="margin:.4em 0"><small>' . esc_html__( 'Numer KSeF:', 'prostafaktura-ksef' ) . '<br><code style="word-break:break-all">' . esc_html( $ref ) . '</code></small></p>';
			}
			return;
		}

		if ( 'issued' === $status ) {
			self::badge( '#b45309', __( '📄 Wystawiona lokalnie — niewysłana do KSeF', 'prostafaktura-ksef' ) );
			$err = (string) $order->get_meta( '_ksef_invoice_error' );
			if ( '' !== $err ) {
				echo '<p style="margin:.5em 0;color:#c0392b"><small><strong>' . esc_html__( 'Wysyłka do KSeF nie powiodła się:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( $err ) . '</small></p>';
			}
			echo '<p style="margin:.2em 0;color:#777"><small>' . esc_html__( 'Popraw przyczynę i wyślij ją ręcznie do KSeF.', 'prostafaktura-ksef' ) . '</small></p>';
			echo self::action_button( 'ksef_send_invoice_now', (int) $order->get_id(), __( 'Wyślij do KSeF', 'prostafaktura-ksef' ), true, __( 'Wysyłam do KSeF…', 'prostafaktura-ksef' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wyjscie zbudowane/escapowane przy zrodle.
			return;
		}

		// queued / sent / pending — wysłana, czekamy na UPO.
		self::badge( '#b45309', __( '⏳ Wysłana do KSeF — czeka na potwierdzenie (UPO)', 'prostafaktura-ksef' ) );
		echo self::action_button( 'ksef_check_invoice_status', (int) $order->get_id(), __( 'Sprawdź status / pobierz UPO', 'prostafaktura-ksef' ), false, __( 'Sprawdzam…', 'prostafaktura-ksef' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wyjscie zbudowane/escapowane przy zrodle.
	}

	/** Stan PO wystawieniu — pełne info o fakturze + status KSeF. */
	private static function render_issued( \WC_Order $order, array $inv ): void {
		$status   = (string) $inv['status'];
		$has_upo  = (int) $inv['upo_len'] > 0;
		$ksef_no  = (string) $inv['ksef_reference_number'];
		$currency = 'PLN';
		$gross    = number_format_i18n( (float) $inv['gross_amount'], 2 );
		$date     = $inv['created_at'] ? date_i18n( 'Y-m-d', strtotime( (string) $inv['created_at'] ) ) : '—';

		echo '<p style="margin:.2em 0"><strong>' . esc_html__( 'Numer:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( (string) ( $inv['invoice_number'] ?: '—' ) ) . '</p>';
		echo '<p style="margin:.2em 0"><strong>' . esc_html__( 'Data wystawienia:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( $date ) . '</p>';
		echo '<p style="margin:.2em 0"><strong>' . esc_html__( 'Kwota brutto:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( $gross . ' ' . $currency ) . '</p>';

		// Status KSeF — czytelny badge.
		echo '<p style="margin:.5em 0 .2em"><strong>' . esc_html__( 'Status KSeF:', 'prostafaktura-ksef' ) . '</strong></p>';
		if ( 'confirmed' === $status ) {
			self::badge( '#22863a', $has_upo
				? __( '✓ Przyjęta przez KSeF — UPO odebrane', 'prostafaktura-ksef' )
				: __( '✓ Przyjęta przez KSeF', 'prostafaktura-ksef' ) );
		} elseif ( 'rejected' === $status ) {
			self::badge( '#c0392b', __( '✗ Odrzucona przez KSeF', 'prostafaktura-ksef' ) );
		} elseif ( 'failed' === $status ) {
			self::badge( '#c0392b', __( '✗ Wysyłka do KSeF nie powiodła się', 'prostafaktura-ksef' ) );
		} elseif ( 'issued' === $status ) {
			self::badge( '#b45309', __( '📄 Wystawiona lokalnie — niewysłana do KSeF', 'prostafaktura-ksef' ) );
		} elseif ( 'offline' === $status ) {
			self::badge( '#b45309', __( '⚠ Tryb offline — do wysłania', 'prostafaktura-ksef' ) );
		} else { // sent / pending / draft
			self::badge( '#b45309', __( '⏳ Wysłana — czeka na UPO', 'prostafaktura-ksef' ) );
		}

		if ( '' !== $ksef_no ) {
			echo '<p style="margin:.4em 0"><small>' . esc_html__( 'Numer KSeF:', 'prostafaktura-ksef' ) . '<br><code style="word-break:break-all">' . esc_html( $ksef_no ) . '</code></small></p>';
		}
		if ( in_array( $status, [ 'rejected', 'failed', 'offline' ], true ) && '' !== (string) $inv['offline_reason'] ) {
			echo '<p style="margin:.4em 0;color:#c0392b"><small><strong>' . esc_html__( 'Powód:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( (string) $inv['offline_reason'] ) . '</small></p>';
		}
		// Faktura wystawiona lokalnie po nieudanej wysyłce — pokaż błąd KSeF z zamówienia.
		$order_err = (string) $order->get_meta( '_ksef_invoice_error' );
		if ( 'issued' === $status && '' !== $order_err ) {
			echo '<p style="margin:.4em 0;color:#c0392b"><small><strong>' . esc_html__( 'Wysyłka do KSeF nie powiodła się:', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( $order_err ) . '</small></p>';
			echo '<p style="margin:.2em 0;color:#777"><small>' . esc_html__( 'Faktura jest wystawiona lokalnie — popraw przyczynę i wyślij ją ręcznie do KSeF.', 'prostafaktura-ksef' ) . '</small></p>';
		}

		// Podgląd faktury.
		$view = admin_url( 'admin.php?page=ksef-manual-invoice&action=view&id=' . (int) $inv['id'] );
		echo '<a href="' . esc_url( $view ) . '" class="button" style="width:100%;text-align:center;margin-top:8px">' . esc_html__( 'Podgląd faktury →', 'prostafaktura-ksef' ) . '</a>';

		// Czeka na UPO → sprawdź status. Wystawiona lokalnie → wyślij do KSeF. Odrzucona/błąd → ponów.
		if ( in_array( $status, [ 'sent', 'pending', 'offline', 'draft' ], true ) ) {
			echo self::action_button( 'ksef_check_invoice_status', (int) $order->get_id(), esc_html__( 'Sprawdź status / pobierz UPO', 'prostafaktura-ksef' ), false, esc_html__( 'Sprawdzam…', 'prostafaktura-ksef' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wyjscie pre-zbudowanego HTML/PDF; dane escapowane przy budowie (esc_html/esc_attr).
		} elseif ( 'issued' === $status ) {
			echo self::action_button( 'ksef_send_invoice_now', (int) $order->get_id(), esc_html__( 'Wyślij do KSeF', 'prostafaktura-ksef' ), true, esc_html__( 'Wysyłam do KSeF…', 'prostafaktura-ksef' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wyjscie pre-zbudowanego HTML/PDF; dane escapowane przy budowie (esc_html/esc_attr).
		} elseif ( in_array( $status, [ 'rejected', 'failed' ], true ) ) {
			echo self::action_button( 'ksef_send_invoice_now', (int) $order->get_id(), esc_html__( 'Wystaw ponownie', 'prostafaktura-ksef' ), true, esc_html__( 'Trwa wystawianie…', 'prostafaktura-ksef' ) ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wyjscie pre-zbudowanego HTML/PDF; dane escapowane przy budowie (esc_html/esc_attr).
		}
	}

	/** Stan PRZED wystawieniem — typ klienta / polityka + przycisk wystawienia. */
	private static function render_not_issued( \WC_Order $order ): void {
		$is_biz  = Checkout_Field::is_business_order( $order );
		$nip     = Checkout_Field::get_nip_from_order( $order );
		$request = Checkout_Field::customer_requested_invoice( $order );
		$mode    = (string) get_option( Order_Trigger::OPTION_PRIVATE_MODE, 'fa_imienna' );

		echo '<p style="margin:.2em 0"><strong>' . esc_html__( 'Typ klienta:', 'prostafaktura-ksef' ) . '</strong> ';
		echo $is_biz
			? '<span style="color:#1f6feb">' . esc_html__( 'firma', 'prostafaktura-ksef' ) . '</span> · NIP <code>' . esc_html( $nip ) . '</code>'
			: '<span style="color:#666">' . esc_html__( 'osoba prywatna', 'prostafaktura-ksef' ) . '</span>';
		echo '</p>';

		// Dane nabywcy do faktury (firma) — z GUS (_ksef_buyer_*), z fallbackiem na pola billing.
		if ( $is_biz ) {
			$bname = (string) $order->get_meta( '_ksef_buyer_name' );
			if ( '' === $bname ) {
				$bname = (string) $order->get_billing_company();
			}
			$bstreet = (string) ( $order->get_meta( '_ksef_buyer_street' ) ?: $order->get_billing_address_1() );
			$bzip    = (string) ( $order->get_meta( '_ksef_buyer_zip' ) ?: $order->get_billing_postcode() );
			$bcity   = (string) ( $order->get_meta( '_ksef_buyer_city' ) ?: $order->get_billing_city() );
			if ( '' !== trim( $bname ) ) {
				$addr = trim( trim( $bstreet ) . ', ' . trim( trim( $bzip ) . ' ' . trim( $bcity ) ), ', ' );
				echo '<p style="margin:.2em 0;color:#555"><small><strong>' . esc_html__( 'Nabywca (faktura):', 'prostafaktura-ksef' ) . '</strong> ' . esc_html( $bname )
					. ( '' !== trim( $bstreet . $bzip . $bcity ) ? ' · ' . esc_html( $addr ) : '' ) . '</small></p>';
			}
		}

		// Kontekst polityki (sensowny tylko dla B2C).
		if ( ! $is_biz ) {
			if ( 'fa_imienna_all' === $mode ) {
				echo '<p style="margin:.2em 0;color:#555"><small>' . esc_html__( 'Polityka: faktura imienna dla każdego klienta.', 'prostafaktura-ksef' ) . '</small></p>';
			} elseif ( 'skip' === $mode ) {
				echo '<p style="margin:.2em 0;color:#b45309"><small>' . esc_html__( 'Polityka: tylko firmy — przy auto-wystawianiu ten klient byłby pominięty (ręcznie możesz wystawić).', 'prostafaktura-ksef' ) . '</small></p>';
			} else {
				echo '<p style="margin:.2em 0"><strong>' . esc_html__( 'Klient chce fakturę:', 'prostafaktura-ksef' ) . '</strong> ' . ( $request ? '✅' : '➖' ) . ' <small style="color:#777">(' . esc_html__( 'polityka: na żądanie', 'prostafaktura-ksef' ) . ')</small></p>';
			}
		}

		echo '<p style="margin-top:10px">' . self::action_button( 'ksef_send_invoice_now', (int) $order->get_id(), esc_html__( 'Wystaw fakturę', 'prostafaktura-ksef' ), true, esc_html__( 'Trwa wystawianie…', 'prostafaktura-ksef' ) ) . '</p>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wyjscie pre-zbudowanego HTML/PDF; dane escapowane przy budowie (esc_html/esc_attr).
		echo '<p style="margin:.2em 0;color:#777"><small>' . esc_html__( 'Faktura zostanie wystawiona i wysłana do KSeF.', 'prostafaktura-ksef' ) . '</small></p>';
	}

	private static function badge( string $color, string $text ): void {
		echo '<span style="display:inline-block;padding:4px 12px;border-radius:99px;font-size:12px;font-weight:600;color:#fff;background:' . esc_attr( $color ) . '">' . esc_html( $text ) . '</span>';
	}

	private static function action_button( string $action, int $order_id, string $label, bool $primary, string $busy = '' ): string {
		$url = wp_nonce_url(
			add_query_arg( [ 'action' => $action, 'order_id' => $order_id ], admin_url( 'admin-post.php' ) ),
			self::NONCE_ACTION,
			self::NONCE_NAME
		);
		$cls  = $primary ? 'button button-primary' : 'button';
		$busy = '' !== $busy ? $busy : __( 'Przetwarzanie…', 'prostafaktura-ksef' );
		// Strona przeładuje się po kliknięciu (link admin-post) — pokaż od razu stan „zajęty",
		// żeby użytkownik widział, że trwa praca, a nie że system się zawiesił.
		$onclick = "if(this.dataset.k)return false;this.dataset.k=1;this.style.pointerEvents='none';this.style.opacity='.65';this.textContent=this.dataset.busy;";
		return '<a href="' . esc_url( $url ) . '" class="' . esc_attr( $cls ) . '" data-busy="' . esc_attr( $busy ) . '" onclick="' . esc_attr( $onclick ) . '" style="width:100%;text-align:center;margin-top:8px">' . esc_html( $label ) . '</a>';
	}

	public static function handle_manual_send(): void {
		if ( ! current_user_can( 'ksef_create_invoice' ) && ! current_user_can( 'ksef_view_outgoing' ) ) {
			wp_die( esc_html__( 'Brak uprawnień.', 'prostafaktura-ksef' ) );
		}
		check_admin_referer( self::NONCE_ACTION, self::NONCE_NAME );

		$order_id = isset( $_GET['order_id'] ) ? (int) $_GET['order_id'] : 0;
		if ( ! $order_id ) {
			wp_die( esc_html__( 'Brak order_id.', 'prostafaktura-ksef' ) );
		}

		$result   = Order_Trigger::send_now( $order_id );
		$redirect = wp_get_referer() ?: admin_url( 'edit.php?post_type=shop_order' );
		$flag     = is_wp_error( $result ) ? 'ksef_error' : 'ksef_sent';
		wp_safe_redirect( add_query_arg( $flag, '1', $redirect ) );
		exit;
	}

	public static function handle_check_status(): void {
		if ( ! current_user_can( 'ksef_create_invoice' ) && ! current_user_can( 'ksef_view_outgoing' ) ) {
			wp_die( esc_html__( 'Brak uprawnień.', 'prostafaktura-ksef' ) );
		}
		check_admin_referer( self::NONCE_ACTION, self::NONCE_NAME );

		if ( class_exists( '\\KSEF\\WordPress\\V2\\Bootstrap' ) ) {
			\KSEF\WordPress\V2\Bootstrap::run_poll_cron();
		}
		$redirect = wp_get_referer() ?: admin_url( 'edit.php?post_type=shop_order' );
		wp_safe_redirect( add_query_arg( 'ksef_checked', '1', $redirect ) );
		exit;
	}
}
