<?php
/**
 * Pro features: citation stats, citations chart, and BibTeX/CSV export.
 *
 * The functions that compute or format data are pure (no WordPress state), so
 * they can be unit-tested directly. Whether they are *used* is decided by the
 * caller via publiton_can_use_pro().
 */

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

/**
 * Sum of citations across all works.
 */
function publiton_total_citations( $works ) {
	$total = 0;
	foreach ( $works as $work ) {
		$total += isset( $work['citations'] ) ? (int) $work['citations'] : 0;
	}
	return $total;
}

/**
 * The h-index: the largest h such that h works each have at least h citations.
 */
function publiton_h_index( $works ) {
	$counts = array();
	foreach ( $works as $work ) {
		$counts[] = isset( $work['citations'] ) ? (int) $work['citations'] : 0;
	}
	rsort( $counts, SORT_NUMERIC );
	$h = 0;
	foreach ( $counts as $i => $count ) {
		if ( $count >= $i + 1 ) {
			$h = $i + 1;
		} else {
			break;
		}
	}
	return $h;
}

/**
 * Citations received per calendar year, aggregated across all works.
 *
 * @return array year (int) => citations (int), ascending by year.
 */
function publiton_citations_by_year( $works ) {
	$agg = array();
	foreach ( $works as $work ) {
		if ( empty( $work['counts_by_year'] ) ) {
			continue;
		}
		foreach ( $work['counts_by_year'] as $year => $count ) {
			$year         = (int) $year;
			$agg[ $year ] = ( isset( $agg[ $year ] ) ? $agg[ $year ] : 0 ) + (int) $count;
		}
	}
	ksort( $agg );
	return $agg;
}

/**
 * Summary header: publication count, total citations, h-index.
 */
function publiton_render_stats_summary( $works ) {
	$pubs      = count( $works );
	$citations = publiton_total_citations( $works );
	$h_index   = publiton_h_index( $works );

	$items = array(
		array( $pubs, _n( 'publication', 'publications', $pubs, 'publiton-auto-publication-updater' ) ),
		array( $citations, _n( 'citation', 'citations', $citations, 'publiton-auto-publication-updater' ) ),
		array( $h_index, __( 'h-index', 'publiton-auto-publication-updater' ) ),
	);

	$html = '<div class="publiton-stats">';
	foreach ( $items as $item ) {
		$html .= '<div class="publiton-stat"><span class="publiton-stat-value">'
			. esc_html( number_format_i18n( $item[0] ) ) . '</span><span class="publiton-stat-label">'
			. esc_html( $item[1] ) . '</span></div>';
	}
	$html .= '</div>';
	return $html;
}

/**
 * A dependency-free inline-SVG bar chart of citations received per year.
 * Returns '' when there is no citation history to plot.
 */
function publiton_render_citations_chart( $works ) {
	$by_year = publiton_citations_by_year( $works );
	if ( empty( $by_year ) ) {
		return '';
	}

	// Fill gap years so the axis is continuous.
	$years = array_keys( $by_year );
	$min   = min( $years );
	$max   = max( $years );
	$data  = array();
	for ( $y = $min; $y <= $max; $y++ ) {
		$data[ $y ] = isset( $by_year[ $y ] ) ? $by_year[ $y ] : 0;
	}

	$peak = max( $data );
	$peak = $peak > 0 ? $peak : 1;

	$width      = 640;
	$height     = 200;
	$pad_bottom = 24;
	$pad_top    = 8;
	$count      = count( $data );
	$slot       = $width / $count;
	$bar_w      = max( 2, $slot * 0.68 );
	$plot_h     = $height - $pad_bottom - $pad_top;

	$bars   = '';
	$labels = '';
	$i      = 0;
	foreach ( $data as $year => $value ) {
		$bar_h = ( $value / $peak ) * $plot_h;
		$x     = ( $i * $slot ) + ( ( $slot - $bar_w ) / 2 );
		$y     = $pad_top + ( $plot_h - $bar_h );
		$bars .= '<rect class="publiton-bar" x="' . round( $x, 2 ) . '" y="' . round( $y, 2 )
			. '" width="' . round( $bar_w, 2 ) . '" height="' . round( $bar_h, 2 ) . '"><title>'
			. esc_html( $year . ': ' . number_format_i18n( $value ) ) . '</title></rect>';
		// Label roughly every ~5 years, plus first and last, to avoid crowding.
		if ( 0 === $i || $count - 1 === $i || 0 === $year % 5 ) {
			$labels .= '<text class="publiton-axis" x="' . round( $x + $bar_w / 2, 2 ) . '" y="' . ( $height - 8 )
				. '" text-anchor="middle">' . esc_html( $year ) . '</text>';
		}
		$i++;
	}

	return '<div class="publiton-chart"><svg viewBox="0 0 ' . $width . ' ' . $height . '" role="img" '
		. 'aria-label="' . esc_attr__( 'Citations received per year', 'publiton-auto-publication-updater' ) . '" '
		. 'preserveAspectRatio="none" xmlns="http://www.w3.org/2000/svg">'
		. $bars . $labels . '</svg></div>';
}

/**
 * A BibTeX citation key: first author surname + year + first title word.
 */
function publiton_bibtex_key( $work, $index ) {
	$surname = '';
	if ( ! empty( $work['authors'][0]['name'] ) ) {
		$parts   = preg_split( '/\s+/', trim( $work['authors'][0]['name'] ) );
		$surname = end( $parts );
	}
	$first_word = '';
	if ( ! empty( $work['title'] ) ) {
		$title_words = preg_split( '/\s+/', trim( $work['title'] ) );
		$first_word  = isset( $title_words[0] ) ? $title_words[0] : '';
	}
	$key = $surname . ( ! empty( $work['year'] ) ? $work['year'] : '' ) . $first_word;
	$key = preg_replace( '/[^A-Za-z0-9]/', '', $key );
	if ( '' === $key ) {
		$key = 'ref' . ( $index + 1 );
	}
	return $key;
}

/**
 * Render the works as a BibTeX document.
 */
function publiton_to_bibtex( $works ) {
	$out  = array();
	$keys = array();
	foreach ( array_values( $works ) as $index => $work ) {
		$key = publiton_bibtex_key( $work, $index );
		// Disambiguate duplicate keys: first stays bare, then a, b, c…
		if ( isset( $keys[ $key ] ) ) {
			$suffix = $keys[ $key ]++;
			$key   .= chr( 97 + ( $suffix % 26 ) );
		} else {
			$keys[ $key ] = 0;
		}

		$names = array();
		foreach ( (array) $work['authors'] as $author ) {
			if ( ! empty( $author['name'] ) ) {
				$names[] = $author['name'];
			}
		}

		$doi = '';
		if ( ! empty( $work['link'] ) && false !== stripos( $work['link'], 'doi.org/' ) ) {
			$doi = preg_replace( '~^https?://(dx\.)?doi\.org/~i', '', $work['link'] );
		}

		$fields = array(
			'title'   => '{' . $work['title'] . '}', // braces preserve capitalization
			'author'  => implode( ' and ', $names ),
			'year'    => ! empty( $work['year'] ) ? (string) $work['year'] : '',
			'journal' => ! empty( $work['venue'] ) ? $work['venue'] : '',
			'doi'     => $doi,
			'url'     => ! empty( $work['link'] ) ? $work['link'] : '',
		);

		$lines = array( '@article{' . $key . ',' );
		foreach ( $fields as $name => $value ) {
			if ( '' === $value ) {
				continue;
			}
			$lines[] = '  ' . $name . ' = {' . $value . '},';
		}
		$lines[] = '}';
		$out[]   = implode( "\n", $lines );
	}
	return implode( "\n\n", $out ) . "\n";
}

/**
 * Render the works as a CSV document (RFC 4180 quoting).
 */
function publiton_to_csv( $works ) {
	$rows   = array();
	$rows[] = array( 'Year', 'Title', 'Authors', 'Venue', 'Citations', 'Link' );
	foreach ( $works as $work ) {
		$names = array();
		foreach ( (array) $work['authors'] as $author ) {
			if ( ! empty( $author['name'] ) ) {
				$names[] = $author['name'];
			}
		}
		$rows[] = array(
			! empty( $work['year'] ) ? (string) $work['year'] : '',
			isset( $work['title'] ) ? $work['title'] : '',
			implode( '; ', $names ),
			isset( $work['venue'] ) ? $work['venue'] : '',
			isset( $work['citations'] ) ? (string) (int) $work['citations'] : '0',
			isset( $work['link'] ) ? $work['link'] : '',
		);
	}

	$lines = array();
	foreach ( $rows as $row ) {
		$cells = array();
		foreach ( $row as $cell ) {
			$cells[] = '"' . str_replace( '"', '""', (string) $cell ) . '"';
		}
		$lines[] = implode( ',', $cells );
	}
	return implode( "\r\n", $lines ) . "\r\n";
}

/**
 * Front-end export handler: streams a BibTeX or CSV file for ?publiton_export=…
 * Only responds when Pro is active; ignored otherwise.
 */
function publiton_handle_export() {
	if ( empty( $_GET['publiton_export'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		return;
	}
	if ( ! publiton_can_use_pro() ) {
		return;
	}
	$format = sanitize_key( wp_unslash( $_GET['publiton_export'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
	if ( ! in_array( $format, array( 'bibtex', 'csv' ), true ) ) {
		return;
	}

	$settings = publiton_get_settings();
	$works    = publiton_fetch_works( $settings, true );
	if ( false === $works ) {
		wp_die( esc_html__( 'The publication list is temporarily unavailable.', 'publiton-auto-publication-updater' ) );
	}

	// Newest first, matching the on-page order.
	usort(
		$works,
		function ( $a, $b ) {
			return strcmp( $b['date'], $a['date'] );
		}
	);

	if ( 'bibtex' === $format ) {
		$body      = publiton_to_bibtex( $works );
		$mime      = 'application/x-bibtex; charset=utf-8';
		$extension = 'bib';
	} else {
		$body      = publiton_to_csv( $works );
		$mime      = 'text/csv; charset=utf-8';
		$extension = 'csv';
	}

	$filename = 'publications-' . gmdate( 'Y-m-d' ) . '.' . $extension;
	nocache_headers();
	header( 'Content-Type: ' . $mime );
	header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
	header( 'Content-Length: ' . strlen( $body ) );
	echo $body; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- file download, not HTML.
	exit;
}
add_action( 'template_redirect', 'publiton_handle_export' );

/**
 * Export links (BibTeX / CSV) for the front-end list.
 */
function publiton_render_export_links() {
	$base = home_url( add_query_arg( array() ) );
	$bib  = add_query_arg( 'publiton_export', 'bibtex', $base );
	$csv  = add_query_arg( 'publiton_export', 'csv', $base );
	return '<div class="publiton-export"><span class="publiton-export-label">'
		. esc_html__( 'Export:', 'publiton-auto-publication-updater' ) . '</span> '
		. '<a href="' . esc_url( $bib ) . '" rel="nofollow">' . esc_html__( 'BibTeX', 'publiton-auto-publication-updater' ) . '</a> '
		. '<a href="' . esc_url( $csv ) . '" rel="nofollow">' . esc_html__( 'CSV', 'publiton-auto-publication-updater' ) . '</a></div>';
}
