<?php
/**
 * Admin page: Faktury sprzedaży (outgoing invoices) — nowy layout.
 *
 * @package KSEF\WordPress\Admin
 */

declare(strict_types=1);

namespace KSEF\WordPress\Admin;

// phpcs:disable WordPress.DB.DirectDatabaseQuery, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders, WordPress.DB.SlowDBQuery, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.Security.NonceVerification -- 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).

class Outgoing_Invoices_List {

	public function render_page(): void {
		if ( ! current_user_can( 'ksef_view_outgoing' ) ) {
			wp_die( esc_html__( 'Brak uprawnień.', 'prostafaktura-ksef' ) );
		}

		Modern_Shell::open( 'faktury-sprzedazy', [
			'crumbs'   => [ 'Faktury', 'Sprzedaży' ],
			'eyebrow'  => '/wp-admin/admin.php?page=ksef-outgoing',
			'title'    => 'Faktury sprzedaży | Hub',
			'subtitle' => 'Wszystkie faktury sprzedaży w jednym widoku — wystawione lokalnie + pobrane z KSeF (wystawione poza wtyczką).',
		] );

		try {
			$this->render_page_inner();
		} finally {
			Modern_Shell::close();
		}
	}

	private function render_page_inner(): void {
		global $wpdb;
		$table = $wpdb->prefix . 'gksef_outgoing_invoices';

		$search        = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '';
		$type_filter   = isset( $_GET['type'] ) ? sanitize_text_field( wp_unslash( $_GET['type'] ) ) : '';
		$pstat_filter  = isset( $_GET['pstatus'] ) ? sanitize_text_field( wp_unslash( $_GET['pstatus'] ) ) : '';
		$source_filter = isset( $_GET['source'] ) ? sanitize_text_field( wp_unslash( $_GET['source'] ) ) : '';
		$paged         = max( 1, intval( wp_unslash( $_GET['paged'] ?? 1 ) ) );
		$per_page     = 25;
		$offset       = ( $paged - 1 ) * $per_page;

		$where = [ '1=1' ];
		if ( '' !== $search ) {
			$like   = '%' . $wpdb->esc_like( $search ) . '%';
			$where[] = $wpdb->prepare( '(invoice_number LIKE %s OR buyer_name LIKE %s OR buyer_nip LIKE %s)', $like, $like, $like );
		}
		if ( in_array( $type_filter, [ 'sent', 'draft', 'confirmed', 'rejected' ], true ) ) {
			$where[] = $wpdb->prepare( 'status = %s', $type_filter );
		}
		if ( in_array( $pstat_filter, [ 'unpaid', 'partial', 'paid' ], true ) ) {
			$where[] = $wpdb->prepare( 'payment_status = %s', $pstat_filter );
		} elseif ( 'overdue' === $pstat_filter ) {
			$where[] = $wpdb->prepare( "payment_status <> 'paid' AND due_date IS NOT NULL AND due_date < %s", gmdate( 'Y-m-d' ) );
		}
		// Filtr źródła: lokalne (wystawione przez wtyczkę) vs importowane (pobrane z KSeF).
		// Gdy user nie ma cap ksef_view_external_invoices — wymuszamy 'local' (nie widzi
		// faktur sprzedażowych pobranych z KSeF wystawionych poza wtyczką).
		if ( ! \KSEF\WordPress\Capabilities::can_view_external() ) {
			$where[] = "(source = 'local' OR source = '' OR source IS NULL)";
		} elseif ( 'local' === $source_filter ) {
			$where[] = "(source = 'local' OR source = '' OR source IS NULL)";
		} elseif ( 'ksef_pulled' === $source_filter ) {
			$where[] = "source = 'ksef_pulled'";
		}
		$where_clause = implode( ' AND ', $where );

		$total = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table} WHERE {$where_clause}" );

		// Liczniki źródeł — pokazywane jako podpis pod tytułem.
		$count_local  = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table} WHERE source = 'local' OR source = '' OR source IS NULL" );
		$count_pulled = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table} WHERE source = 'ksef_pulled'" );
		$rows  = $wpdb->get_results(
			"SELECT * FROM {$table} WHERE {$where_clause}
			 ORDER BY COALESCE(submission_timestamp, created_at) DESC
			 LIMIT {$per_page} OFFSET {$offset}",
			ARRAY_A
		);
		$rows = is_array( $rows ) ? $rows : [];

		$nonce      = wp_create_nonce( 'ksef-nonce' );
		$cred_index = self::credentials_index();
		$qs         = static function ( array $extra ) {
			// Pomocnik do budowania URLi filtrów z zachowaniem pozostałych parametrów GET.
			$base = $_GET;
			foreach ( $extra as $k => $v ) {
				if ( null === $v || '' === $v ) {
					unset( $base[ $k ] );
				} else {
					$base[ $k ] = $v;
				}
			}
			$base['page'] = 'ksef-outgoing';
			return esc_url( admin_url( 'admin.php?' . http_build_query( $base ) ) );
		};
		$tab_all  = ! $source_filter;
		$tab_loc  = 'local' === $source_filter;
		$tab_pull = 'ksef_pulled' === $source_filter;
		?>
		<form method="get" id="ksef-filters-form" style="display:contents;">
			<input type="hidden" name="page" value="ksef-outgoing">
			<input type="hidden" name="source" id="source-hidden" value="<?php echo esc_attr( $source_filter ); ?>">

			<!-- Toolbar -->
			<div class="list-toolbar">
				<div class="search-box">
					<div class="input-wrap">
						<input class="input with-icon" type="search" name="s" value="<?php echo esc_attr( $search ); ?>" placeholder="<?php esc_attr_e( 'Szukaj po numerze, NIP, nabywcy…', 'prostafaktura-ksef' ); ?>">
						<span class="lic"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg></span>
					</div>
				</div>


				<select name="type" class="input" style="width:auto; max-width:170px;" data-autosubmit>
					<option value=""><?php esc_html_e( 'Status: wszystkie', 'prostafaktura-ksef' ); ?></option>
					<option value="sent" <?php selected( $type_filter, 'sent' ); ?>><?php esc_html_e( 'Wysłane', 'prostafaktura-ksef' ); ?></option>
					<option value="draft" <?php selected( $type_filter, 'draft' ); ?>><?php esc_html_e( 'Drafty', 'prostafaktura-ksef' ); ?></option>
					<option value="confirmed" <?php selected( $type_filter, 'confirmed' ); ?>><?php esc_html_e( 'Potwierdzone', 'prostafaktura-ksef' ); ?></option>
					<option value="rejected" <?php selected( $type_filter, 'rejected' ); ?>><?php esc_html_e( 'Odrzucone', 'prostafaktura-ksef' ); ?></option>
				</select>
				<select name="pstatus" class="input" style="width:auto; max-width:170px;" data-autosubmit>
					<option value=""><?php esc_html_e( 'Płatność: wszystkie', 'prostafaktura-ksef' ); ?></option>
					<option value="unpaid"  <?php selected( $pstat_filter, 'unpaid' ); ?>><?php esc_html_e( 'Nieopłacone', 'prostafaktura-ksef' ); ?></option>
					<option value="partial" <?php selected( $pstat_filter, 'partial' ); ?>><?php esc_html_e( 'Częściowo', 'prostafaktura-ksef' ); ?></option>
					<option value="paid"    <?php selected( $pstat_filter, 'paid' ); ?>><?php esc_html_e( 'Opłacone', 'prostafaktura-ksef' ); ?></option>
					<option value="overdue" <?php selected( $pstat_filter, 'overdue' ); ?>><?php esc_html_e( 'Przeterminowane', 'prostafaktura-ksef' ); ?></option>
				</select>

				<div style="margin-left:auto; display:flex; gap:6px;">
					<a href="https://prostafakturaksef.pl/cennik" target="_blank" rel="noopener" class="btn btn-ghost btn-sm" title="<?php esc_attr_e( 'Import faktur sprzedaży z KSeF (z innych systemów) dostępny w wersji Pro', 'prostafaktura-ksef' ); ?>">
						<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg>
						<?php esc_html_e( 'Pobierz z KSeF', 'prostafaktura-ksef' ); ?> 🔒
					</a>
					<a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-manual-invoice' ) ); ?>" class="btn btn-primary btn-sm">
						<svg viewBox="0 0 24 24" fill="none" stroke="currentColor"><path d="M12 5v14M5 12h14"/></svg>
						<?php esc_html_e( 'Wystaw fakturę', 'prostafaktura-ksef' ); ?>
					</a>
				</div>
			</div>
		</form>

		<!-- LIST -->
		<div class="list list--outgoing">
			<div class="list-row head">
				<span class="sel"><input type="checkbox" class="ksef-select-all" title="<?php esc_attr_e( 'Zaznacz wszystkie na tej stronie', 'prostafaktura-ksef' ); ?>"></span>
				<span class="date"><?php esc_html_e( 'Data wystawienia', 'prostafaktura-ksef' ); ?></span>
				<span><?php esc_html_e( 'Kontrahent / Źródło', 'prostafaktura-ksef' ); ?></span>
				<span><?php esc_html_e( 'Numer', 'prostafaktura-ksef' ); ?></span>
				<span style="text-align:right"><?php esc_html_e( 'Kwota brutto', 'prostafaktura-ksef' ); ?></span>
				<span style="text-align:center"><?php esc_html_e( 'Płatność', 'prostafaktura-ksef' ); ?></span>
				<span style="text-align:center">KSeF</span>
				<span></span>
			</div>

			<?php if ( empty( $rows ) ) : ?>
				<div class="empty">
					<div class="ic">
						<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6"/></svg>
					</div>
					<b><?php esc_html_e( 'Brak faktur do wyświetlenia', 'prostafaktura-ksef' ); ?></b>
					<p style="margin:4px 0 14px;"><?php esc_html_e( 'Wystaw swoją pierwszą fakturę i wyślij ją bezpośrednio do KSeF.', 'prostafaktura-ksef' ); ?></p>
					<a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-manual-invoice' ) ); ?>" class="btn btn-primary btn-sm">+ <?php esc_html_e( 'Wystaw pierwszą fakturę', 'prostafaktura-ksef' ); ?></a>
				</div>
			<?php else : foreach ( $rows as $inv ) :
				$payload = $inv['payload_json'] ? json_decode( (string) \KSEF\WordPress\Crypto::decrypt_from_storage( $inv['payload_json'] ), true ) : [];
				$issue_date = $payload['issue_date'] ?? ( $inv['created_at'] ? gmdate( 'd.m.Y', strtotime( $inv['created_at'] ) ) : '' );
				if ( strtotime( $issue_date ) ) {
					$issue_date_short = gmdate( 'd.m', strtotime( $issue_date ) );
				} else {
					$issue_date_short = $issue_date;
				}
				$cred       = $cred_index[ (int) $inv['credential_id'] ] ?? null;
				$lokal_name = $cred['name'] ?? ( 'NIP ' . ( $cred['nip'] ?? '?' ) );
				$source     = (string) ( $inv['source'] ?? 'local' );
				$is_pulled  = ( 'ksef_pulled' === $source );
				$src_class  = $is_pulled ? 'import' : 'manual';
				$src_label  = $is_pulled
					? ( ! empty( $inv['external_issuer'] ) ? esc_html( (string) $inv['external_issuer'] ) . ' · import' : 'Import z KSeF' )
					: esc_html( (string) $lokal_name );
				$gross      = (float) $inv['gross_amount'];
				$is_neg     = $gross < 0;
				$inv_number = $inv['invoice_number'] ?: '#' . (int) $inv['id'];
				$is_kor     = false !== stripos( $inv_number, 'KOR' ) || false !== stripos( $inv_number, ' K' );
				// Fallback do payload_json (już wczytany wyżej) gdy kolumna buyer_name pusta —
				// lista zawsze pokaże nabywcę, gdy jest znany w danych faktury.
				$buyer_name = $inv['buyer_name'] ?: ( (string) ( $payload['buyer']['name'] ?? '' ) ?: '—' );
				$buyer_nip  = $inv['buyer_nip'] ?: (string) ( $payload['buyer']['nip'] ?? '' );
				?>
				<div class="list-row ksef-row-clickable" data-invoice-id="<?php echo (int) $inv['id']; ?>" data-type="outgoing">
					<span class="sel"><input type="checkbox" class="ksef-row-check" value="<?php echo (int) $inv['id']; ?>"></span>
					<span class="date"><?php echo esc_html( strtotime( (string) $issue_date ) ? gmdate( 'd.m.Y', strtotime( (string) $issue_date ) ) : $issue_date_short ); ?></span>
					<span class="nabywca">
						<b><?php echo esc_html( $buyer_name ); ?></b>
						<small>
							<?php if ( '' !== $buyer_nip ) : ?>NIP <?php echo esc_html( $buyer_nip ); ?> · <?php endif; ?>
							<span class="src <?php echo esc_attr( $src_class ); ?>" title="<?php echo $is_pulled ? esc_attr__( 'Pobrane z KSeF (poza wtyczką)', 'prostafaktura-ksef' ) : esc_attr__( 'Wystawione lokalnie', 'prostafaktura-ksef' ); ?>">
								<span class="d"></span><?php echo $src_label; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $src_label juz zescapowany powyzej ?>
							</span>
						</small>
					</span>
					<span class="num">
						<?php echo esc_html( $inv_number ); ?>
						<?php if ( $is_kor ) : ?>
							<span style="font-weight:400; color:var(--ink-4); font-size:11px; margin-left:4px;">(korekta)</span>
						<?php endif; ?>
					</span>
					<span class="amt <?php echo $is_neg ? 'neg' : ''; ?>">
						<?php echo $is_neg ? '−' : ''; ?><?php echo esc_html( number_format_i18n( abs( $gross ), 2 ) ); ?> <?php echo esc_html( $inv['currency'] ?: 'PLN' ); ?>
					</span>
					<span style="text-align:center" class="pay-cell">
						<span class="pay-toggle" data-invoice-id="<?php echo (int) $inv['id']; ?>" data-type="outgoing" data-status="<?php echo esc_attr( (string) ( $inv['payment_status'] ?? 'unpaid' ) ); ?>">
							<?php echo self::payment_badge( (string) ( $inv['payment_status'] ?? 'unpaid' ), (string) ( $inv['due_date'] ?? '' ) ); // phpcs:ignore ?>
							<svg class="caret" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="m6 9 6 6 6-6"/></svg>
						</span>
						<div class="pay-menu">
							<button type="button" class="pay-opt" data-status="paid"><span class="status-pill paid">Opłacona</span></button>
							<button type="button" class="pay-opt" data-status="partial"><span class="status-pill draft">Częściowo</span></button>
							<button type="button" class="pay-opt" data-status="unpaid"><span class="status-pill">Nieopłacona</span></button>
						</div>
					</span>
					<span style="text-align:center">
						<?php echo self::ksef_badge( (string) $inv['status'], ! empty( $inv['ksef_reference_number'] ) ); // phpcs:ignore ?>
					</span>
					<span class="ksef-row-actions" data-invoice-id="<?php echo (int) $inv['id']; ?>" style="position:relative;">
						<button type="button" class="menu ksef-action-trigger" aria-label="Akcje">
							<svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="5" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="19" cy="12" r="1.5"/></svg>
						</button>
						<div class="ksef-action-menu">
							<?php if ( in_array( ( $inv['status'] ?? '' ), [ 'draft', 'rejected' ], true ) ) : ?>
								<a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-manual-invoice&action=edit&id=' . (int) $inv['id'] ) ); ?>" class="ksef-action-item">✏️ <?php echo 'rejected' === ( $inv['status'] ?? '' ) ? esc_html__( 'Popraw i wyślij', 'prostafaktura-ksef' ) : esc_html__( 'Edytuj', 'prostafaktura-ksef' ); ?></a>
							<?php else : ?>
								<a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-manual-invoice&action=view&id=' . (int) $inv['id'] ) ); ?>" class="ksef-action-item">👁 <?php esc_html_e( 'Podgląd', 'prostafaktura-ksef' ); ?></a>
																<?php endif; ?>
							<button type="button" class="ksef-action-item ksef-copy-trigger" data-invoice-id="<?php echo (int) $inv['id']; ?>">📋 <?php esc_html_e( 'Kopiuj jako nowy szkic', 'prostafaktura-ksef' ); ?></button>
							<a href="<?php echo esc_url( add_query_arg( [ 'action' => 'ksef_invoice_pdf', 'invoice_id' => (int) $inv['id'], '_ajax_nonce' => $nonce ], admin_url( 'admin-ajax.php' ) ) ); ?>" target="_blank" class="ksef-action-item">📄 <?php esc_html_e( 'Pobierz PDF', 'prostafaktura-ksef' ); ?></a>
							<button type="button" class="ksef-action-item ksef-send-pdf-trigger" data-invoice-id="<?php echo (int) $inv['id']; ?>">📧 <?php esc_html_e( 'Wyślij PDF mailem', 'prostafaktura-ksef' ); ?></button>
							<?php if ( 'draft' !== ( $inv['status'] ?? '' ) ) : ?>
								<a href="<?php echo esc_url( admin_url( 'admin.php?page=ksef-manual-invoice&action=correct&id=' . (int) $inv['id'] ) ); ?>" class="ksef-action-item">📝 <?php esc_html_e( 'Wystaw korektę', 'prostafaktura-ksef' ); ?></a>
							<?php endif; ?>
							<?php if ( ! empty( $inv['ksef_reference_number'] ) ) : ?>
								<a href="<?php echo esc_url( add_query_arg( [ 'action' => 'ksef_download_upo', 'invoice_id' => (int) $inv['id'], 'format' => 'pdf', '_ajax_nonce' => $nonce ], admin_url( 'admin-ajax.php' ) ) ); ?>" target="_blank" class="ksef-action-item">📜 <?php esc_html_e( 'UPO PDF', 'prostafaktura-ksef' ); ?></a>
								<a href="<?php echo esc_url( add_query_arg( [ 'action' => 'ksef_download_upo', 'invoice_id' => (int) $inv['id'], 'format' => 'xml', '_ajax_nonce' => $nonce ], admin_url( 'admin-ajax.php' ) ) ); ?>" target="_blank" class="ksef-action-item">📑 <?php esc_html_e( 'UPO XML', 'prostafaktura-ksef' ); ?></a>
							<?php endif; ?>
							<div class="ksef-action-sep"></div>
							<button type="button" class="ksef-action-item ksef-action-danger ksef-delete-trigger"
								data-invoice-id="<?php echo (int) $inv['id']; ?>"
								data-invoice-number="<?php echo esc_attr( (string) ( $inv['invoice_number'] ?? '#' . $inv['id'] ) ); ?>"
								data-in-ksef="<?php echo ! empty( $inv['ksef_reference_number'] ) ? '1' : '0'; ?>"
								data-ksef-ref="<?php echo esc_attr( (string) ( $inv['ksef_reference_number'] ?? '' ) ); ?>"
								data-is-draft="<?php echo ( 'draft' === ( $inv['status'] ?? '' ) ) ? '1' : '0'; ?>">
								🗑 <?php echo ( 'draft' === ( $inv['status'] ?? '' ) ) ? esc_html__( 'Usuń szkic', 'prostafaktura-ksef' ) : esc_html__( 'Usuń z bazy', 'prostafaktura-ksef' ); ?>
							</button>
						</div>
					</span>
				</div>
			<?php endforeach; endif; ?>
		</div>

		<?php
		$total_pages = max( 1, (int) ceil( $total / $per_page ) );
		if ( $total_pages > 1 ) :
			?>
			<div class="pagination">
				<span><?php
					printf(
						// translators: %1$d = numer pierwszej pozycji na stronie, %2$d = ostatniej, %3$s = laczna liczba faktur
						esc_html__( 'Wyświetlanie %1$d–%2$d z %3$s faktur', 'prostafaktura-ksef' ),
						(int) ( $offset + 1 ),
						(int) min( $total, $offset + $per_page ),
						'<b>' . esc_html( number_format_i18n( $total ) ) . '</b>'
					);
					?></span>
				<div class="pages">
					<?php
					$pl = paginate_links( [
						'base'    => add_query_arg( 'paged', '%#%' ),
						'format'  => '',
						'current' => $paged,
						'total'   => $total_pages,
						'type'    => 'array',
						'prev_text' => '←',
						'next_text' => '→',
					] );
					if ( $pl ) {
						foreach ( $pl as $link ) {
							echo wp_kses_post( $link );
						}
					}
					?>
				</div>
			</div>
		<?php endif; ?>


		<!-- Detail modal -->
		<div id="ksef-detail-modal" class="ksef-modal-overlay" style="display:none;">
			<div class="ksef-modal-card">
				<button class="ksef-modal-close" type="button">&times;</button>
				<div id="ksef-modal-body" style="max-height:74vh;overflow-y:auto;"></div>
			</div>
		</div>

		<!-- Modal: Wyslij PDF mailem (temat/tresc edytowalne) -->
		<div id="ksef-email-modal" class="ksef-modal-overlay" style="display:none;">
			<div class="ksef-modal-card" style="max-width:580px;">
				<button class="ksef-modal-close" type="button">&times;</button>
				<h3 style="margin:0 0 4px;font-size:17px;">📧 Wyślij fakturę PDF mailem</h3>
				<p style="margin:0 0 14px;color:#6b7280;font-size:13px;">Temat i treść są wstępnie wypełnione szablonem — możesz je dowolnie zmienić przed wysłaniem.</p>
				<input type="hidden" id="em-invoice-id">
				<label style="display:block;font-size:12px;font-weight:600;margin:8px 0 3px;color:#374151;">Adres e-mail odbiorcy</label>
				<input type="email" id="em-to" placeholder="klient@example.com" style="width:100%;padding:8px 10px;border:1px solid #d8dade;border-radius:8px;box-sizing:border-box;">
				<label style="display:block;font-size:12px;font-weight:600;margin:12px 0 3px;color:#374151;">Temat</label>
				<input type="text" id="em-subject" style="width:100%;padding:8px 10px;border:1px solid #d8dade;border-radius:8px;box-sizing:border-box;">
				<label style="display:block;font-size:12px;font-weight:600;margin:12px 0 3px;color:#374151;">Treść wiadomości</label>
				<textarea id="em-body" rows="8" style="width:100%;padding:8px 10px;border:1px solid #d8dade;border-radius:8px;box-sizing:border-box;font-family:inherit;font-size:13px;line-height:1.5;"></textarea>
				<div style="display:flex;justify-content:flex-end;gap:8px;margin-top:16px;">
					<button type="button" class="btn btn-sm" id="em-cancel">Anuluj</button>
					<button type="button" class="btn btn-primary btn-sm" id="em-send">📧 Wyślij</button>
				</div>
			</div>
		</div>
		<!-- Pasek akcji masowych (pojawia się po zaznaczeniu) -->
		<div id="ksef-bulkbar" class="ksef-bulkbar" style="display:none;">
			<span class="ksef-bulkbar-count"><b id="ksef-bulk-n">0</b> <?php esc_html_e( 'zaznaczono', 'prostafaktura-ksef' ); ?></span>
			<button type="button" class="btn btn-sm" id="ksef-bulk-clear"><?php esc_html_e( 'Wyczyść', 'prostafaktura-ksef' ); ?></button>
			<button type="button" class="btn btn-sm ksef-btn-danger" id="ksef-bulk-delete"><?php esc_html_e( 'Usuń zaznaczone', 'prostafaktura-ksef' ); ?></button>
			<span class="ksef-bulkbar-sep"></span>
			<button type="button" class="btn btn-sm ksef-btn-danger-outline" id="ksef-bulk-delete-all">🗑 <?php esc_html_e( 'Usuń wszystkie faktury sprzedaży', 'prostafaktura-ksef' ); ?></button>
		</div>

		<?php ob_start(); ?>
		.pay-cell { position:relative; }
		.pay-toggle { display:inline-flex; align-items:center; gap:4px; cursor:pointer; }
		.pay-toggle .caret { color:var(--ink-4, #888); transition:transform .15s; }
		.pay-cell.open .pay-toggle .caret { transform:rotate(180deg); }
		.pay-menu { display:none; position:absolute; top:calc(100% + 4px); left:50%; transform:translateX(-50%); background:#fff; border:1px solid var(--ink-6, #E7E5E1); border-radius:10px; box-shadow:0 12px 32px rgba(10,10,11,.12); z-index:60; padding:4px; min-width:160px; }
		.pay-cell.open .pay-menu { display:flex; flex-direction:column; gap:2px; }
		.pay-opt { background:none; border:none; padding:6px 8px; cursor:pointer; border-radius:6px; text-align:left; display:flex; align-items:center; }
		.pay-opt:hover { background:var(--surface-2, #F7F5F0); }

		.ksef-row-actions { position: relative; display: inline-flex; justify-content:flex-end; }
		.ksef-action-trigger.menu { background:#fff; border:1px solid var(--ink-6, #E7E5E1); padding:6px 8px; cursor:pointer; color:var(--ink-3, #555); border-radius:8px; line-height:1; display:inline-flex; align-items:center; gap:4px; transition:all .15s; }
		.ksef-action-trigger.menu:hover { background:var(--surface-2, #F7F5F0); color:var(--ink, #0A0A0B); }
		.ksef-action-menu { display:none; position:absolute; right:0; top:calc(100% + 4px); background:#fff; border:1px solid var(--ink-6, #E7E5E1); border-radius:10px; min-width:220px; box-shadow:0 12px 32px rgba(10,10,11,0.10); z-index:100; padding:4px; text-align:left; }
		.ksef-row-actions.open .ksef-action-menu { display:block; }
		.ksef-action-item { display:block; width:100%; padding:8px 12px; font-size:13px; color:var(--ink, #0A0A0B); text-decoration:none; background:none; border:none; cursor:pointer; text-align:left; border-radius:6px; font-family:inherit; }
		.ksef-action-item:hover { background:var(--surface-2, #F7F5F0); }
		.ksef-action-item.ksef-action-danger { color:#DC2626; }
		.ksef-action-item.ksef-action-danger:hover { background:#FEE2E2; color:#991B1B; }
		.ksef-action-sep { height:1px; background:var(--ink-6, #E7E5E1); margin:4px 0; }

		.ksef-modal-overlay { position:fixed; inset:0; background:rgba(10,10,11,0.55); display:flex; align-items:center; justify-content:center; z-index:9999; }
		.ksef-modal-card { background:#fff; border-radius:14px; width:90%; max-width:880px; padding:22px 26px; position:relative; max-height:88vh; overflow-y:auto; box-shadow:0 24px 60px rgba(10,10,11,.25); }
		.ksef-modal-close { position:absolute; top:12px; right:14px; background:none; border:none; font-size:22px; cursor:pointer; color:var(--ink-3, #555); }
		<?php Modern_Shell::inline_style( 'ksef-outgoing-list', ob_get_clean() ); ob_start(); ?>
		(function(){
			const ajaxUrl = <?php echo wp_json_encode( admin_url( 'admin-ajax.php' ) ); ?>;
			const nonce = <?php echo wp_json_encode( $nonce ); ?>;

			async function openDetail(id){
				const modal = document.getElementById('ksef-detail-modal');
				const body = document.getElementById('ksef-modal-body');
				body.innerHTML = '<p>Ładowanie…</p>';
				modal.style.display = 'flex';
				try {
					const fd = new FormData();
					fd.append('action', 'ksef_get_invoice_detail');
					fd.append('_ajax_nonce', nonce);
					fd.append('invoice_id', id);
					fd.append('type', 'outgoing');
					const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
					const j = await r.json();
					if (j.success) body.innerHTML = j.data.html || '<p>Brak danych.</p>';
					else body.innerHTML = '<p>Błąd: ' + (j.data?.message || 'nieznany') + '</p>';
				} catch(err) { body.innerHTML = '<p>Network error: ' + err + '</p>'; }
			}
			// Kompatybilność: stare wywołania .ksef-detail-btn (w modalach płatności)
			document.querySelectorAll('.ksef-detail-btn').forEach(btn => {
				btn.addEventListener('click', function(e){ e.preventDefault(); openDetail(btn.getAttribute('data-invoice-id')); });
			});
			// Klik w DOWOLNE miejsce wiersza otwiera podgląd — pomijając menu akcji,
			// pay-toggle i elementy interaktywne (a/button/input).
			const viewBase = <?php echo wp_json_encode( admin_url( 'admin.php?page=ksef-manual-invoice&action=view&id=' ) ); ?>;
			document.querySelectorAll('.ksef-row-clickable').forEach(row => {
				row.addEventListener('click', function(e){
					if (e.target.closest('.ksef-row-actions') || e.target.closest('.pay-cell') || e.target.closest('a,button,input,select,label')) return;
					window.location.href = viewBase + row.getAttribute('data-invoice-id');
				});
			});

			document.querySelectorAll('.ksef-modal-close').forEach(b => b.addEventListener('click', () => b.closest('.ksef-modal-overlay').style.display = 'none'));

			// === Masowe usuwanie (checkboxy + pasek akcji) ===
			const bulkbar  = document.getElementById('ksef-bulkbar');
			const bulkN    = document.getElementById('ksef-bulk-n');
			const selAll   = document.querySelector('.ksef-select-all');
			function rowChecks(){ return Array.from(document.querySelectorAll('.ksef-row-check')); }
			function selectedIds(){ return rowChecks().filter(c => c.checked).map(c => c.value); }
			function refreshBulk(){
				const ids = selectedIds();
				bulkN.textContent = ids.length;
				bulkbar.style.display = ids.length ? 'flex' : 'none';
				if (selAll){ const all = rowChecks(); selAll.checked = all.length && all.every(c => c.checked); selAll.indeterminate = !selAll.checked && all.some(c => c.checked); }
			}
			rowChecks().forEach(c => c.addEventListener('change', refreshBulk));
			if (selAll) selAll.addEventListener('change', () => { rowChecks().forEach(c => c.checked = selAll.checked); refreshBulk(); });
			// klik w sam checkbox nie ma otwierać podglądu (stopPropagation)
			document.querySelectorAll('.list--outgoing .sel').forEach(s => s.addEventListener('click', e => e.stopPropagation()));
			document.getElementById('ksef-bulk-clear')?.addEventListener('click', () => { rowChecks().forEach(c => c.checked = false); refreshBulk(); });

			async function bulkDelete(payload, confirmMsg){
				if (!confirm(confirmMsg)) return;
				const fd = new FormData();
				fd.append('action','ksef_bulk_delete_invoices');
				fd.append('_ajax_nonce', nonce);
				fd.append('type','outgoing');
				for (const k in payload) {
					if (Array.isArray(payload[k])) payload[k].forEach(v => fd.append(k+'[]', v));
					else fd.append(k, payload[k]);
				}
				try {
					const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
					const j = await r.json();
					if (j.success){
						let msg = 'Usunięto ' + j.data.deleted + ' faktur z bazy wtyczki.';
						if (j.data.in_ksef > 0) msg += '\n\nUWAGA: ' + j.data.in_ksef + ' z nich było wysłanych do KSeF — te faktury POZOSTAJĄ w urzędowym rejestrze MF (usunięto tylko lokalny rekord).';
						alert(msg);
						location.reload();
					} else {
						alert('Błąd: ' + (j.data?.message || 'nieznany'));
					}
				} catch(err){ alert('Network error: ' + err); }
			}

			document.getElementById('ksef-bulk-delete')?.addEventListener('click', () => {
				const ids = selectedIds();
				if (!ids.length) return;
				bulkDelete({ ids: ids }, 'Usunąć ' + ids.length + ' zaznaczonych faktur z bazy wtyczki?\n\nUWAGA: faktury wysłane do KSeF POZOSTANĄ w urzędowym rejestrze MF — usuwamy wyłącznie lokalny rekord wraz z załącznikami.');
			});
			document.getElementById('ksef-bulk-delete-all')?.addEventListener('click', () => {
				bulkDelete({ all: '1' }, 'Usunąć WSZYSTKIE faktury sprzedaży z bazy wtyczki (wszystkie strony)?\n\nTej operacji NIE MOŻNA cofnąć. Faktury wysłane do KSeF POZOSTANĄ w urzędowym rejestrze MF — usuwamy wyłącznie lokalne rekordy wraz z załącznikami.');
			});

			// === Per-row akcje (menu ⋮) ===
			function closeRowMenus(){
				document.querySelectorAll('.ksef-row-actions.open').forEach(w => {
					w.classList.remove('open');
					const m = w.querySelector('.ksef-action-menu');
					if (m) m.removeAttribute('style');
				});
			}
			document.querySelectorAll('.ksef-action-trigger').forEach(btn => {
				btn.addEventListener('click', function(e){
					e.stopPropagation();
					const wrapper = btn.closest('.ksef-row-actions');
					const willOpen = !wrapper.classList.contains('open');
					closeRowMenus();
					if (!willOpen) return;
					wrapper.classList.add('open');
					const menu = wrapper.querySelector('.ksef-action-menu');
					if (!menu) return;
					// Pozycjonuj jako fixed - menu nie jest ucinane przez overflow kontenera listy.
					menu.style.position = 'fixed';
					menu.style.right = 'auto';
					const br = btn.getBoundingClientRect();
					const mh = menu.offsetHeight, mw = menu.offsetWidth;
					let top = br.bottom + 4;
					if (top + mh > window.innerHeight - 8) top = Math.max(8, br.top - mh - 4);
					let left = br.right - mw;
					if (left < 8) left = 8;
					menu.style.top = top + 'px';
					menu.style.left = left + 'px';
				});
			});
			document.addEventListener('click', () => {
				closeRowMenus();
				document.querySelectorAll('.pay-cell.open').forEach(c => c.classList.remove('open'));
			});
			window.addEventListener('scroll', closeRowMenus, true);
			window.addEventListener('resize', closeRowMenus);

			// === Inline zmiana statusu płatności ===
			document.querySelectorAll('.pay-toggle').forEach(t => {
				t.addEventListener('click', function(e){
					e.stopPropagation();
					const cell = t.closest('.pay-cell');
					document.querySelectorAll('.pay-cell.open').forEach(c => { if (c !== cell) c.classList.remove('open'); });
					cell.classList.toggle('open');
				});
			});
			document.querySelectorAll('.pay-opt').forEach(opt => {
				opt.addEventListener('click', async function(e){
					e.stopPropagation();
					const cell = opt.closest('.pay-cell');
					const toggle = cell.querySelector('.pay-toggle');
					const status = opt.dataset.status;
					const fd = new FormData();
					fd.append('action', 'ksef_set_payment_status');
					fd.append('_ajax_nonce', nonce);
					fd.append('invoice_id', toggle.dataset.invoiceId);
					fd.append('type', toggle.dataset.type);
					fd.append('status', status);
					try {
						const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
						const j = await r.json();
						if (j.success) {
							// Podmień pill w toggle (bez reloadu)
							const pillMap = {
								paid:    '<span class="status-pill paid">Opłacona</span>',
								partial: '<span class="status-pill draft">Częściowo</span>',
								unpaid:  '<span class="status-pill">Nieopłacona</span>',
							};
							toggle.querySelector('.status-pill').outerHTML = pillMap[status] || pillMap.unpaid;
							toggle.dataset.status = status;
							cell.classList.remove('open');
						} else {
							alert('Błąd: ' + (j.data?.message || 'nieznany'));
						}
					} catch(err) { alert('Network: ' + err); }
				});
			});

			// === Usuń fakturę z bazy ===
			document.querySelectorAll('.ksef-delete-trigger').forEach(b => {
				b.addEventListener('click', async function(){
					const inKsef = b.dataset.inKsef === '1';
					const num    = b.dataset.invoiceNumber || 'tej faktury';
					const ksefRef = b.dataset.ksefRef || '';
					let prompt = '';
					if (inKsef) {
						prompt = 'Usuwasz fakturę ' + num + ' TYLKO z lokalnej bazy wtyczki.\n\n'
							+ '⚠ Faktura została już wysłana do KSeF (nr ref: ' + ksefRef + ') i pozostanie w urzędowym rejestrze — KSeF nie pozwala na usunięcie wysłanych faktur. '
							+ 'Aby formalnie wycofać fakturę użyj korekty lub anulacji w KSeF.\n\n'
							+ 'Kontynuować usunięcie z bazy lokalnej?';
					} else {
						const isDraft = b.dataset.isDraft === '1';
						prompt = (isDraft ? 'Usunąć szkic ' : 'Usunąć fakturę ') + num + '? Tej operacji nie da się cofnąć.';
					}
					if (! confirm(prompt)) return;
					const id = b.dataset.invoiceId;
					const fd = new FormData();
					fd.append('action', 'ksef_delete_invoice');
					fd.append('_ajax_nonce', nonce);
					fd.append('invoice_id', id);
					try {
						const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
						const j = await r.json();
						if (j.success) {
							b.closest('.list-row').remove();
							if (j.data?.was_in_ksef) {
								alert('Faktura ' + num + ' usunięta z bazy lokalnej. W KSeF (nr ref: ' + ksefRef + ') nadal istnieje — to urzędowy rejestr.');
							}
						} else {
							alert('Błąd: ' + (j.data?.message || 'nieznany'));
						}
					} catch(err) { alert('Network: ' + err); }
				});
			});

			// === Kopiuj fakturę jako nowy szkic ===
			document.querySelectorAll('.ksef-copy-trigger').forEach(b => {
				b.addEventListener('click', async function(){
					const id = b.dataset.invoiceId;
					if (!id) return;
					const orig = b.textContent; b.disabled = true; b.textContent = 'Kopiowanie…';
					try {
						const fd = new FormData();
						fd.append('action', 'ksef_copy_invoice');
						fd.append('_ajax_nonce', nonce);
						fd.append('invoice_id', id);
						const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
						const j = await r.json();
						if (j.success && j.data && j.data.draft_id) {
							window.location.href = <?php echo wp_json_encode( admin_url( 'admin.php?page=ksef-manual-invoice&action=edit&id=' ) ); ?> + j.data.draft_id;
						} else {
							alert('Nie udało się skopiować faktury:\n' + ((j.data && j.data.message) || 'nieznany błąd'));
							b.disabled = false; b.textContent = orig;
						}
					} catch(e){ alert('Błąd połączenia przy kopiowaniu.'); b.disabled = false; b.textContent = orig; }
				});
			});

			// === Wyślij PDF mailem (modal z edytowalnym tematem/treścią) ===
			const emModal = document.getElementById('ksef-email-modal');
			function closeEmModal(){ if (emModal) emModal.style.display = 'none'; }
			if (emModal){
				emModal.querySelector('.ksef-modal-close')?.addEventListener('click', closeEmModal);
				document.getElementById('em-cancel')?.addEventListener('click', closeEmModal);
				emModal.addEventListener('click', function(e){ if (e.target === emModal) closeEmModal(); });
			}
			document.querySelectorAll('.ksef-send-pdf-trigger').forEach(b => {
				b.addEventListener('click', async function(){
					if (!emModal) return;
					const id = b.dataset.invoiceId;
					document.getElementById('em-invoice-id').value = id;
					document.getElementById('em-to').value = '';
					document.getElementById('em-subject').value = '';
					document.getElementById('em-body').value = 'Ładowanie…';
					emModal.style.display = 'flex';
					try {
						const fd = new FormData();
						fd.append('action', 'ksef_invoice_email_preview');
						fd.append('_ajax_nonce', nonce);
						fd.append('invoice_id', id);
						const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
						const j = await r.json();
						document.getElementById('em-to').value = (j.success && j.data.to) ? j.data.to : (b.dataset.suggestEmail || '');
						document.getElementById('em-subject').value = (j.success && j.data.subject) ? j.data.subject : '';
						document.getElementById('em-body').value = (j.success && j.data.body) ? j.data.body : '';
					} catch(e){ document.getElementById('em-body').value = ''; }
					document.getElementById('em-to').focus();
				});
			});
			document.getElementById('em-send')?.addEventListener('click', async function(){
				const id = document.getElementById('em-invoice-id').value;
				const to = document.getElementById('em-to').value.trim();
				if (!to){ alert('Podaj adres e-mail odbiorcy.'); return; }
				const btn = this; const orig = btn.textContent;
				btn.disabled = true; btn.textContent = 'Wysyłanie…';
				try {
					const fd = new FormData();
					fd.append('action', 'ksef_invoice_email');
					fd.append('_ajax_nonce', nonce);
					fd.append('invoice_id', id);
					fd.append('to', to);
					fd.append('subject', document.getElementById('em-subject').value);
					fd.append('body', document.getElementById('em-body').value);
					const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
					const j = await r.json();
					if (j.success){ closeEmModal(); alert('✓ Wysłano PDF na: ' + (j.data?.sent_to || to)); }
					else { alert('Błąd: ' + (j.data?.message || 'nieznany')); }
				} catch(err){ alert('Network: ' + err); }
				finally { btn.disabled = false; btn.textContent = orig; }
			});

			// Auto-submit form on filter change
			document.querySelectorAll('select[data-autosubmit]').forEach(s => s.addEventListener('change', () => s.closest('form').submit()));
			const searchInput = document.querySelector('input[type="search"][name="s"]');
			if (searchInput) {
				let tmr; searchInput.addEventListener('input', () => { clearTimeout(tmr); tmr = setTimeout(() => searchInput.closest('form').submit(), 500); });
			}

			// Delegated payment/email handlers (działają wewnątrz modala)
			document.addEventListener('submit', async function(e){
				if (e.target.classList && e.target.classList.contains('ksef-add-payment-form')) {
					e.preventDefault();
					const form = e.target;
					const fd = new FormData(form);
					fd.append('action', 'ksef_add_payment');
					fd.append('_ajax_nonce', nonce);
					fd.append('invoice_id', form.dataset.invoiceId);
					try {
						const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
						const j = await r.json();
						if (j.success) openDetail(form.dataset.invoiceId);
						else alert('Błąd: ' + (j.data?.message || 'nieznany'));
					} catch(err){ alert('Network: ' + err); }
				}
				if (e.target.classList && e.target.classList.contains('ksef-send-email-form')) {
					e.preventDefault();
					const form = e.target;
					const fd = new FormData(form);
					fd.append('action', 'ksef_invoice_email');
					fd.append('_ajax_nonce', nonce);
					fd.append('invoice_id', form.dataset.invoiceId);
					try {
						const r = await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
						const j = await r.json();
						if (j.success) alert('Wysłano PDF na: ' + (j.data?.sent_to || ''));
						else alert('Błąd: ' + (j.data?.message || 'nieznany'));
					} catch(err){ alert('Network: ' + err); }
				}
			});
			document.addEventListener('click', async function(e){
				if (e.target.classList && e.target.classList.contains('ksef-del-payment')) {
					if (!confirm('Usunąć płatność?')) return;
					const fd = new FormData();
					fd.append('action', 'ksef_delete_payment');
					fd.append('_ajax_nonce', nonce);
					fd.append('payment_id', e.target.dataset.paymentId);
					fd.append('invoice_id', e.target.dataset.invoiceId);
					await fetch(ajaxUrl, { method:'POST', body:fd, credentials:'same-origin' });
					openDetail(e.target.dataset.invoiceId);
				}
			});
		})();
		<?php Modern_Shell::inline_script( 'ksef-outgoing-list', ob_get_clean() ); ?>
		<?php
	}

	private static function credentials_index(): array {
		global $wpdb;
		$rows = $wpdb->get_results( "SELECT id, nip, name FROM {$wpdb->prefix}gksef_credentials", ARRAY_A );
		$out  = [];
		foreach ( (array) $rows as $r ) {
			$out[ (int) $r['id'] ] = $r;
		}
		return $out;
	}

	private static function added_by_label( array $inv ): string {
		// W przyszłości dodać kolumnę created_by w outgoing. Na razie: user z payload lub aktualny admin.
		$user = wp_get_current_user();
		if ( $user && $user->ID ) {
			return (string) ( $user->display_name ?: $user->user_login );
		}
		return '';
	}

	private static function payment_badge( string $status, string $due_date ): string {
		$is_overdue = $due_date && '0000-00-00' !== $due_date && strtotime( $due_date ) < strtotime( 'today' ) && $status !== 'paid';
		if ( $is_overdue ) {
			return '<span class="status-pill danger">Po terminie</span>';
		}
		if ( 'paid' === $status ) {
			return '<span class="status-pill paid">Opłacona</span>';
		}
		if ( 'partial' === $status ) {
			return '<span class="status-pill draft">Częściowo</span>';
		}
		return '<span class="status-pill">Nieopłacona</span>';
	}

	private static function ksef_badge( string $status, bool $has_reference ): string {
		if ( 'confirmed' === $status || $has_reference ) {
			return '<span class="status-pill paid">UPO</span>';
		}
		if ( 'sent' === $status || 'sent_from_draft' === $status ) {
			return '<span class="status-pill sent">Wysłana</span>';
		}
		if ( 'rejected' === $status ) {
			return '<span class="status-pill danger">Odrzucona</span>';
		}
		return '<span class="status-pill draft">Draft</span>';
	}
}
