<?php
/**
 * Automatyczne linkowanie faktur zakupowych do zamówień WooCommerce
 *
 * Łączy faktury pobrane z KSeF z odpowiadającymi im zamówieniami.
 *
 * @package KSEF\WordPress
 */

namespace KSEF\WordPress;

// 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).

/**
 * Invoice_Auto_Linker — auto-link incoming invoices to WC orders
 *
 * Obsługuje:
 * - Matching seller_nip w WC_Order custom field (_billing_nip)
 * - Sprawdzenie daty (issue_date vs order_date)
 * - Update status → 'linked'
 * - Link reversal (unlink)
 */
class Invoice_Auto_Linker {

	/**
	 * Automatycznie linkuj fakturę do zamówienia
	 *
	 * @param int $incoming_invoice_id ID faktury zakupowej.
	 * @return int|false ID zamówienia lub false
	 */
	public static function auto_link_invoice( $incoming_invoice_id ) {
		global $wpdb;

		// Pobierz fakturę
		$invoice = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}gksef_incoming_invoices WHERE id = %d",
				$incoming_invoice_id
			),
			ARRAY_A
		);

		if ( ! $invoice ) {
			return false;
		}

		// Szukaj zamówienia
		$order_id = self::find_matching_order(
			$invoice['seller_nip'],
			$invoice['buyer_nip'],
			$invoice['issue_date']
		);

		if ( ! $order_id ) {
			return false;
		}

		// Linkuj
		return self::link_invoice_to_order( $incoming_invoice_id, $order_id );
	}

	/**
	 * Szukaj pasującego zamówienia
	 *
	 * Logika matching:
	 * 1. Szukaj WC_Order gdzie _billing_nip = seller_nip z faktury
	 * 2. Sprawdzić czy order_date jest bliska issue_date (tolerance: 7 dni)
	 * 3. Zwrócić pierwszy pasujący order_id
	 *
	 * Date tolerance: 7 dni (bezpiecznie)
	 * - Faktura zwykle wystawiana tego samego dnia co zamówienie
	 * - 7 dni jest bezpiecznym buforem bez false positives
	 *
	 * @param string $seller_nip NIP sprzedawcy.
	 * @param string $buyer_nip NIP nabywcy (opcjonalnie).
	 * @param string $issue_date Data wystawienia faktury.
	 * @return int|false Order ID lub false
	 */
	public static function find_matching_order( $seller_nip, $buyer_nip, $issue_date ) {
		global $wpdb;

		// Sanityzuj NIP
		$seller_nip = preg_replace( '/[^0-9]/', '', (string) $seller_nip );

		if ( strlen( $seller_nip ) !== 10 || ! function_exists( 'wc_get_orders' ) ) {
			return false;
		}

		// Szukaj zamówień po _billing_nip (HPOS-safe — wc_get_orders obsługuje postmeta i tabele HPOS).
		$order_ids = wc_get_orders(
			[
				'limit'      => 10,
				'return'     => 'ids',
				'meta_key'   => '_billing_nip', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				'meta_value' => $seller_nip,    // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
			]
		);

		if ( empty( $order_ids ) ) {
			return false;
		}

		// Filtruj po dacie
		$issue_datetime = strtotime( (string) $issue_date );
		$date_tolerance = 7 * DAY_IN_SECONDS; // 7 dni tolerancji

		foreach ( $order_ids as $order_id ) {
			$order = wc_get_order( $order_id );
			if ( ! $order ) {
				continue;
			}

			$created    = $order->get_date_created();
			$order_date = $created ? $created->getTimestamp() : 0;

			if ( $order_date && abs( $order_date - $issue_datetime ) <= $date_tolerance ) {
				return (int) $order_id;
			}
		}

		return false;
	}

	/**
	 * Linkuj fakturę do zamówienia
	 *
	 * @param int $invoice_id ID faktury.
	 * @param int $order_id ID zamówienia.
	 * @return int|false ID zamówienia lub false
	 */
	public static function link_invoice_to_order( $invoice_id, $order_id ) {
		global $wpdb;

		// Update invoice status → linked
		$result = $wpdb->update(
			$wpdb->prefix . 'gksef_incoming_invoices',
			[
				'processing_status' => 'linked',
			],
			[ 'id' => $invoice_id ]
		);

		if ( ! $result ) {
			return false;
		}

		// Update order meta (HPOS-safe — wc_get_order zamiast post-meta).
		$order = wc_get_order( $order_id );
		if ( $order ) {
			$order->update_meta_data( '_ksef_incoming_invoice_id', $invoice_id );
			$order->save();
		}

		// Log
		do_action( 'ksef_invoice_linked', $invoice_id, $order_id );

		return $order_id;
	}

	/**
	 * Pobierz linkowane faktury dla zamówienia
	 *
	 * @param int $order_id ID zamówienia.
	 * @return array Lista faktur
	 */
	public static function get_linked_invoices( $order_id ) {
		global $wpdb;

		$order      = wc_get_order( $order_id );
		$invoice_id = $order ? $order->get_meta( '_ksef_incoming_invoice_id' ) : '';

		if ( ! $invoice_id ) {
			return [];
		}

		$invoice = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}gksef_incoming_invoices WHERE id = %d",
				$invoice_id
			),
			ARRAY_A
		);

		return $invoice ? [ $invoice ] : [];
	}

	/**
	 * Usuń link między fakturą a zamówieniem
	 *
	 * @param int $invoice_id ID faktury.
	 * @return bool
	 */
	public static function unlink_invoice( $invoice_id ) {
		global $wpdb;

		// Pobierz order_id (HPOS-safe — wc_get_orders zamiast WP_Query po shop_order).
		$order_id = null;
		$found    = function_exists( 'wc_get_orders' ) ? wc_get_orders( [
			'limit'      => 1,
			'return'     => 'ids',
			'meta_key'   => '_ksef_incoming_invoice_id', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
			'meta_value' => $invoice_id,                 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
		] ) : [];
		if ( ! empty( $found ) ) {
			$order_id = (int) $found[0];
		}

		// Update invoice status → pending
		$result = $wpdb->update(
			$wpdb->prefix . 'gksef_incoming_invoices',
			[
				'processing_status' => 'pending',
			],
			[ 'id' => $invoice_id ]
		);

		if ( ! $result ) {
			return false;
		}

		// Remove meta (HPOS-safe).
		if ( $order_id ) {
			$order = wc_get_order( $order_id );
			if ( $order ) {
				$order->delete_meta_data( '_ksef_incoming_invoice_id' );
				$order->save();
			}
		}

		// Log
		do_action( 'ksef_invoice_unlinked', $invoice_id, $order_id );

		return true;
	}

	/**
	 * Wyświetl linked invoices w WC order metabox
	 *
	 * @param int $order_id ID zamówienia.
	 * @return void
	 */
	public static function display_linked_invoices_in_order( $order_id ) {
		$invoices = self::get_linked_invoices( $order_id );

		if ( empty( $invoices ) ) {
			return;
		}

		echo '<div class="ksef-linked-invoices" style="background: #ccf0dd; padding: 15px; border-radius: 4px; margin-top: 15px;">';
		echo '<h4>' . esc_html__( 'Powiązane faktury KSeF', 'prostafaktura-ksef' ) . '</h4>';
		echo '<ul>';

		foreach ( $invoices as $invoice ) {
			echo '<li>';
			echo esc_html( $invoice['invoice_number'] ) . ' (' . esc_html( $invoice['seller_nip'] ) . ')';
			echo '<br>';
			echo '<small style="color: #666;">';
			echo esc_html__( 'Data:', 'prostafaktura-ksef' ) . ' ' . esc_html( $invoice['issue_date'] ) . ' | ';
			echo esc_html__( 'Kwota:', 'prostafaktura-ksef' ) . ' ' . esc_html( number_format_i18n( $invoice['gross_amount'], 2 ) ) . ' PLN';
			echo '</small>';
			echo '</li>';
		}

		echo '</ul>';
		echo '</div>';
	}
}
